@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,328 @@
|
|
|
1
|
+
import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
|
|
2
|
+
import { v3_quaternion_apply } from "../../../../core/geom/vec3/v3_quaternion_apply.js";
|
|
3
|
+
import { v3_quaternion_apply_inverse } from "../../../../core/geom/vec3/v3_quaternion_apply_inverse.js";
|
|
4
|
+
import {
|
|
5
|
+
CCR_FEATURE,
|
|
6
|
+
CCR_FRICTION,
|
|
7
|
+
CCR_INFLATION,
|
|
8
|
+
CCR_KIND,
|
|
9
|
+
CCR_PARAM_0,
|
|
10
|
+
CCR_PARAM_1,
|
|
11
|
+
CCR_PARAM_2,
|
|
12
|
+
CCR_PARAM_3,
|
|
13
|
+
CCR_PREV_QW,
|
|
14
|
+
CCR_PREV_QX,
|
|
15
|
+
CCR_PREV_QY,
|
|
16
|
+
CCR_PREV_QZ,
|
|
17
|
+
CCR_PREV_TX,
|
|
18
|
+
CCR_PREV_TY,
|
|
19
|
+
CCR_PREV_TZ,
|
|
20
|
+
CCR_QW,
|
|
21
|
+
CCR_QX,
|
|
22
|
+
CCR_QY,
|
|
23
|
+
CCR_QZ,
|
|
24
|
+
CCR_STRIDE,
|
|
25
|
+
CCR_TX,
|
|
26
|
+
CCR_TY,
|
|
27
|
+
CCR_TZ
|
|
28
|
+
} from "../collider/ClothColliderRecord.js";
|
|
29
|
+
import { cloth_collider_refit_bounds } from "../collider/cloth_collider_bounds.js";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* # Bringing the world's colliders into a cloth's frame
|
|
33
|
+
*
|
|
34
|
+
* The index holds every live cloth collider in **world** coordinates; the
|
|
35
|
+
* solver works in the cloth's own **local** frame (§12 — garment-sized
|
|
36
|
+
* coordinates are what makes `Float32` particle state ample, and the local
|
|
37
|
+
* frame is what makes §7 P7's inertia model natural). So once per cloth per
|
|
38
|
+
* step, the colliders that could touch it are queried out of the index and
|
|
39
|
+
* rewritten into its frame.
|
|
40
|
+
*
|
|
41
|
+
* ## Both poses go into the *current* anchor frame
|
|
42
|
+
*
|
|
43
|
+
* A record carries where the collider was and where it is. Both are converted
|
|
44
|
+
* using the anchor's pose **now**, not each with the anchor pose of its own
|
|
45
|
+
* step, so what the sweep interpolates is the collider's motion *relative to
|
|
46
|
+
* the cloth's frame*. That is the motion the particles actually see: the frame
|
|
47
|
+
* change has already been applied to them by `move_local_frame`, scaled by
|
|
48
|
+
* `ClothDynamics#inertia`, before the step begins.
|
|
49
|
+
*
|
|
50
|
+
* The alternative — converting each pose in its own frame — would make a
|
|
51
|
+
* collider appear to move whenever the anchor did, so a character running past
|
|
52
|
+
* a static wall would sweep the wall through their own cape.
|
|
53
|
+
*
|
|
54
|
+
* ## The query box
|
|
55
|
+
*
|
|
56
|
+
* The cloth's own particle bounds, fattened by how far a contact reaches, and
|
|
57
|
+
* then by how far the solver will let a particle travel in one step. The second
|
|
58
|
+
* term is what stops a fast cloth outrunning its own broadphase within the step
|
|
59
|
+
* it was gathered for; it is the velocity clamp of §7 P1 read as a distance,
|
|
60
|
+
* which is the quantity it was built out of.
|
|
61
|
+
*
|
|
62
|
+
* @author Alex Goldring
|
|
63
|
+
* @copyright Company Named Limited (c) 2026
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Query the index and rewrite the overlapping colliders into the cloth's frame.
|
|
68
|
+
*
|
|
69
|
+
* @param {ClothInstance} instance filled in place — `collider_table`,
|
|
70
|
+
* `collider_key` and `collider_count`
|
|
71
|
+
* @param {ClothColliderIndex} index
|
|
72
|
+
* @param {number} reach how far a particle may travel this step, metres
|
|
73
|
+
* @returns {number} how many colliders were gathered
|
|
74
|
+
*/
|
|
75
|
+
export function cloth_gather_colliders(instance, index, reach) {
|
|
76
|
+
const state = instance.state;
|
|
77
|
+
|
|
78
|
+
const particle_count = state.particle_count;
|
|
79
|
+
const position = state.position;
|
|
80
|
+
|
|
81
|
+
let min_x = Infinity;
|
|
82
|
+
let min_y = Infinity;
|
|
83
|
+
let min_z = Infinity;
|
|
84
|
+
let max_x = -Infinity;
|
|
85
|
+
let max_y = -Infinity;
|
|
86
|
+
let max_z = -Infinity;
|
|
87
|
+
|
|
88
|
+
for (let i = 0; i < particle_count; i++) {
|
|
89
|
+
const p = i * 3;
|
|
90
|
+
|
|
91
|
+
const x = position[p];
|
|
92
|
+
const y = position[p + 1];
|
|
93
|
+
const z = position[p + 2];
|
|
94
|
+
|
|
95
|
+
if (x < min_x) { min_x = x; }
|
|
96
|
+
if (y < min_y) { min_y = y; }
|
|
97
|
+
if (z < min_z) { min_z = z; }
|
|
98
|
+
if (x > max_x) { max_x = x; }
|
|
99
|
+
if (y > max_y) { max_y = y; }
|
|
100
|
+
if (z > max_z) { max_z = z; }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (particle_count === 0) {
|
|
104
|
+
instance.collider_count = 0;
|
|
105
|
+
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const margin = reach + state.contact_radius * 2;
|
|
110
|
+
|
|
111
|
+
min_x -= margin;
|
|
112
|
+
min_y -= margin;
|
|
113
|
+
min_z -= margin;
|
|
114
|
+
max_x += margin;
|
|
115
|
+
max_y += margin;
|
|
116
|
+
max_z += margin;
|
|
117
|
+
|
|
118
|
+
// The anchor pose the particles were carried into this step, not the live
|
|
119
|
+
// component — those are the same value by the time this runs, and the
|
|
120
|
+
// cached pair is the one `move_local_frame` used.
|
|
121
|
+
const anchor_x = instance.anchor_translation[0];
|
|
122
|
+
const anchor_y = instance.anchor_translation[1];
|
|
123
|
+
const anchor_z = instance.anchor_translation[2];
|
|
124
|
+
|
|
125
|
+
const qx = instance.anchor_rotation[0];
|
|
126
|
+
const qy = instance.anchor_rotation[1];
|
|
127
|
+
const qz = instance.anchor_rotation[2];
|
|
128
|
+
const qw = instance.anchor_rotation[3];
|
|
129
|
+
|
|
130
|
+
// The local box's eight corners, in world. A rotated box is not a box, so
|
|
131
|
+
// the world query volume is the bounds of the rotated one rather than the
|
|
132
|
+
// rotation of the bounds.
|
|
133
|
+
let world_min_x = Infinity;
|
|
134
|
+
let world_min_y = Infinity;
|
|
135
|
+
let world_min_z = Infinity;
|
|
136
|
+
let world_max_x = -Infinity;
|
|
137
|
+
let world_max_y = -Infinity;
|
|
138
|
+
let world_max_z = -Infinity;
|
|
139
|
+
|
|
140
|
+
for (let corner = 0; corner < 8; corner++) {
|
|
141
|
+
v3_quaternion_apply(
|
|
142
|
+
CORNER, 0,
|
|
143
|
+
(corner & 1) === 0 ? min_x : max_x,
|
|
144
|
+
(corner & 2) === 0 ? min_y : max_y,
|
|
145
|
+
(corner & 4) === 0 ? min_z : max_z,
|
|
146
|
+
qx, qy, qz, qw
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const x = CORNER[0] + anchor_x;
|
|
150
|
+
const y = CORNER[1] + anchor_y;
|
|
151
|
+
const z = CORNER[2] + anchor_z;
|
|
152
|
+
|
|
153
|
+
if (x < world_min_x) { world_min_x = x; }
|
|
154
|
+
if (y < world_min_y) { world_min_y = y; }
|
|
155
|
+
if (z < world_min_z) { world_min_z = z; }
|
|
156
|
+
if (x > world_max_x) { world_max_x = x; }
|
|
157
|
+
if (y > world_max_y) { world_max_y = y; }
|
|
158
|
+
if (z > world_max_z) { world_max_z = z; }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const cloth = instance.cloth;
|
|
162
|
+
|
|
163
|
+
const found = index.query(
|
|
164
|
+
HANDLES, world_min_x, world_min_y, world_min_z,
|
|
165
|
+
world_max_x, world_max_y, world_max_z,
|
|
166
|
+
cloth.layer, cloth.mask
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (instance.collider_table === null || instance.collider_table.length < found * CCR_STRIDE) {
|
|
170
|
+
let capacity = 8;
|
|
171
|
+
|
|
172
|
+
while (capacity < found) {
|
|
173
|
+
capacity *= 2;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
instance.collider_table = new Float32Array(capacity * CCR_STRIDE);
|
|
177
|
+
instance.collider_key = new Int32Array(capacity);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const table = instance.collider_table;
|
|
181
|
+
const keys = instance.collider_key;
|
|
182
|
+
|
|
183
|
+
const source = index.table;
|
|
184
|
+
|
|
185
|
+
for (let i = 0; i < found; i++) {
|
|
186
|
+
const handle = HANDLES[i];
|
|
187
|
+
|
|
188
|
+
const from = handle * CCR_STRIDE;
|
|
189
|
+
const to = i * CCR_STRIDE;
|
|
190
|
+
|
|
191
|
+
keys[i] = handle;
|
|
192
|
+
|
|
193
|
+
table[to + CCR_KIND] = source[from + CCR_KIND];
|
|
194
|
+
table[to + CCR_PARAM_0] = source[from + CCR_PARAM_0];
|
|
195
|
+
table[to + CCR_PARAM_1] = source[from + CCR_PARAM_1];
|
|
196
|
+
table[to + CCR_PARAM_2] = source[from + CCR_PARAM_2];
|
|
197
|
+
table[to + CCR_PARAM_3] = source[from + CCR_PARAM_3];
|
|
198
|
+
table[to + CCR_FEATURE] = source[from + CCR_FEATURE];
|
|
199
|
+
table[to + CCR_FRICTION] = source[from + CCR_FRICTION];
|
|
200
|
+
table[to + CCR_INFLATION] = source[from + CCR_INFLATION];
|
|
201
|
+
|
|
202
|
+
localise(
|
|
203
|
+
table, to + CCR_TX, to + CCR_QX,
|
|
204
|
+
source[from + CCR_TX], source[from + CCR_TY], source[from + CCR_TZ],
|
|
205
|
+
source[from + CCR_QX], source[from + CCR_QY], source[from + CCR_QZ], source[from + CCR_QW],
|
|
206
|
+
anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
localise(
|
|
210
|
+
table, to + CCR_PREV_TX, to + CCR_PREV_QX,
|
|
211
|
+
source[from + CCR_PREV_TX], source[from + CCR_PREV_TY], source[from + CCR_PREV_TZ],
|
|
212
|
+
source[from + CCR_PREV_QX], source[from + CCR_PREV_QY],
|
|
213
|
+
source[from + CCR_PREV_QZ], source[from + CCR_PREV_QW],
|
|
214
|
+
anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
cloth_collider_refit_bounds(table, i, CCR_STRIDE);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
instance.collider_count = found;
|
|
221
|
+
|
|
222
|
+
return found;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Write a world pose into a record's translation and rotation slots, expressed
|
|
227
|
+
* in the anchor's frame.
|
|
228
|
+
*
|
|
229
|
+
* @param {Float32Array} table
|
|
230
|
+
* @param {number} translation_slot
|
|
231
|
+
* @param {number} rotation_slot
|
|
232
|
+
* @param {number} tx
|
|
233
|
+
* @param {number} ty
|
|
234
|
+
* @param {number} tz
|
|
235
|
+
* @param {number} rx
|
|
236
|
+
* @param {number} ry
|
|
237
|
+
* @param {number} rz
|
|
238
|
+
* @param {number} rw
|
|
239
|
+
* @param {number} anchor_x
|
|
240
|
+
* @param {number} anchor_y
|
|
241
|
+
* @param {number} anchor_z
|
|
242
|
+
* @param {number} qx
|
|
243
|
+
* @param {number} qy
|
|
244
|
+
* @param {number} qz
|
|
245
|
+
* @param {number} qw
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
function localise(
|
|
249
|
+
table, translation_slot, rotation_slot,
|
|
250
|
+
tx, ty, tz, rx, ry, rz, rw,
|
|
251
|
+
anchor_x, anchor_y, anchor_z, qx, qy, qz, qw
|
|
252
|
+
) {
|
|
253
|
+
v3_quaternion_apply_inverse(
|
|
254
|
+
LOCAL_TRANSLATION, 0,
|
|
255
|
+
tx - anchor_x, ty - anchor_y, tz - anchor_z,
|
|
256
|
+
qx, qy, qz, qw
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
table[translation_slot] = LOCAL_TRANSLATION[0];
|
|
260
|
+
table[translation_slot + 1] = LOCAL_TRANSLATION[1];
|
|
261
|
+
table[translation_slot + 2] = LOCAL_TRANSLATION[2];
|
|
262
|
+
|
|
263
|
+
quat3_multiply(LOCAL_ROTATION, 0, -qx, -qy, -qz, qw, rx, ry, rz, rw);
|
|
264
|
+
|
|
265
|
+
table[rotation_slot] = LOCAL_ROTATION[0];
|
|
266
|
+
table[rotation_slot + 1] = LOCAL_ROTATION[1];
|
|
267
|
+
table[rotation_slot + 2] = LOCAL_ROTATION[2];
|
|
268
|
+
table[rotation_slot + 3] = LOCAL_ROTATION[3];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Whether any collider overlapping this cloth moved between the previous step
|
|
273
|
+
* and this one — §7 P5's "wake on collider motion", asked without waking.
|
|
274
|
+
*
|
|
275
|
+
* A sleeping cloth is not stepped and not written back, so something has to
|
|
276
|
+
* notice when the world it was resting against moves. This is that something,
|
|
277
|
+
* and it is a broadphase query plus a pose comparison: cheaper than a step by
|
|
278
|
+
* three orders of magnitude, which is what makes sleep worth having at all.
|
|
279
|
+
*
|
|
280
|
+
* @param {ClothInstance} instance
|
|
281
|
+
* @param {ClothColliderIndex} index
|
|
282
|
+
* @returns {boolean}
|
|
283
|
+
*/
|
|
284
|
+
export function cloth_colliders_moved(instance, index) {
|
|
285
|
+
const found = cloth_gather_colliders(instance, index, 0);
|
|
286
|
+
|
|
287
|
+
const table = instance.collider_table;
|
|
288
|
+
|
|
289
|
+
for (let i = 0; i < found; i++) {
|
|
290
|
+
const r = i * CCR_STRIDE;
|
|
291
|
+
|
|
292
|
+
if (table[r + CCR_TX] !== table[r + CCR_PREV_TX]
|
|
293
|
+
|| table[r + CCR_TY] !== table[r + CCR_PREV_TY]
|
|
294
|
+
|| table[r + CCR_TZ] !== table[r + CCR_PREV_TZ]
|
|
295
|
+
|| table[r + CCR_QX] !== table[r + CCR_PREV_QX]
|
|
296
|
+
|| table[r + CCR_QY] !== table[r + CCR_PREV_QY]
|
|
297
|
+
|| table[r + CCR_QZ] !== table[r + CCR_PREV_QZ]
|
|
298
|
+
|| table[r + CCR_QW] !== table[r + CCR_PREV_QW]) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @type {number[]}
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
const HANDLES = [];
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* @type {Float64Array}
|
|
314
|
+
* @private
|
|
315
|
+
*/
|
|
316
|
+
const CORNER = new Float64Array(3);
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* @type {Float64Array}
|
|
320
|
+
* @private
|
|
321
|
+
*/
|
|
322
|
+
const LOCAL_TRANSLATION = new Float64Array(3);
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @type {Float64Array}
|
|
326
|
+
* @private
|
|
327
|
+
*/
|
|
328
|
+
const LOCAL_ROTATION = new Float64Array(4);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fill `blended_position` and `blended_rotation` from the solved particles.
|
|
3
|
+
*
|
|
4
|
+
* Both are in the **cloth's own frame**: the position is the particle lerped
|
|
5
|
+
* towards its animated one by `Cloth#blend`, and the rotation is the swing
|
|
6
|
+
* composed onto the animated orientation. Node 0 — the anchor — is the origin of
|
|
7
|
+
* that frame, so its rotation is the identity rather than anything read off it.
|
|
8
|
+
*
|
|
9
|
+
* @param {ClothInstance} instance
|
|
10
|
+
* @returns {void}
|
|
11
|
+
*/
|
|
12
|
+
export function cloth_reconstruct_pose(instance: ClothInstance): void;
|
|
13
|
+
//# sourceMappingURL=cloth_reconstruct_pose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloth_reconstruct_pose.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_reconstruct_pose.js"],"names":[],"mappings":"AA6DA;;;;;;;;;;GAUG;AACH,iEAFa,IAAI,CAqEhB"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { quat3_multiply } from "../../../../core/geom/3d/quaternion/quat3_multiply.js";
|
|
2
|
+
import { quat3_nlerp } from "../../../../core/geom/3d/quaternion/quat3_nlerp.js";
|
|
3
|
+
import { quat3_shortest_arc } from "../../../../core/geom/3d/quaternion/quat3_shortest_arc.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* # From particles to a pose — the half of the write-back that is arithmetic
|
|
7
|
+
*
|
|
8
|
+
* A particle has a position and no orientation, so a node's rotation has to be
|
|
9
|
+
* reconstructed. This module does that, in the cloth's own frame, into
|
|
10
|
+
* {@link ClothInstance#blended_position} and
|
|
11
|
+
* {@link ClothInstance#blended_rotation} — and then stops. What is done with the
|
|
12
|
+
* result is the *writer's* business, and there are two of them: the entity path
|
|
13
|
+
* writes a `Transform64` and a `TransformAttachment`, the rig path writes a
|
|
14
|
+
* `Node3D`.
|
|
15
|
+
*
|
|
16
|
+
* M3 split it out for exactly that reason. §11 claims "the solver is identical
|
|
17
|
+
* either way; only seeding and write-back differ", and a second copy of the
|
|
18
|
+
* swing reconstruction would have made that claim true of the solver and false
|
|
19
|
+
* of everything above it.
|
|
20
|
+
*
|
|
21
|
+
* ## Rotation is a swing on top of the animated orientation
|
|
22
|
+
*
|
|
23
|
+
* q_node = swing(d_animated → d_simulated) ⊗ q_animated
|
|
24
|
+
*
|
|
25
|
+
* Twist about the link is inherited from the animation rather than invented,
|
|
26
|
+
* which is right: a chain of particles carries no twist degree of freedom and
|
|
27
|
+
* any twist this code produced would be a fabrication. And it degenerates
|
|
28
|
+
* correctly — at `blend = 0` the simulated direction *is* the animated one, the
|
|
29
|
+
* swing is the identity, and the reconstruction reproduces the authored pose
|
|
30
|
+
* exactly.
|
|
31
|
+
*
|
|
32
|
+
* A node with a parent and children has two links and two swings, and takes the
|
|
33
|
+
* half-way rotation between them. A leaf has only its parent's. Without that,
|
|
34
|
+
* every link points at its child and a two-link chain reads as a hinge with a
|
|
35
|
+
* corner in it.
|
|
36
|
+
*
|
|
37
|
+
* @author Alex Goldring
|
|
38
|
+
* @copyright Company Named Limited (c) 2026
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Scratch for one node's swing quaternions. Module-level: the reconstruction
|
|
43
|
+
* allocates nothing.
|
|
44
|
+
* @type {Float64Array}
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
const SWING = new Float64Array(12);
|
|
48
|
+
|
|
49
|
+
/** Where the parent-driven swing sits in {@link SWING}. @private */
|
|
50
|
+
const SWING_PARENT = 0;
|
|
51
|
+
/** Where the child-driven swing sits in {@link SWING}. @private */
|
|
52
|
+
const SWING_CHILD = 4;
|
|
53
|
+
/** Where the blended swing sits. @private */
|
|
54
|
+
const SWING_OUT = 8;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @type {Float64Array}
|
|
58
|
+
* @private
|
|
59
|
+
*/
|
|
60
|
+
const DIRECTION = new Float64Array(12);
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Fill `blended_position` and `blended_rotation` from the solved particles.
|
|
64
|
+
*
|
|
65
|
+
* Both are in the **cloth's own frame**: the position is the particle lerped
|
|
66
|
+
* towards its animated one by `Cloth#blend`, and the rotation is the swing
|
|
67
|
+
* composed onto the animated orientation. Node 0 — the anchor — is the origin of
|
|
68
|
+
* that frame, so its rotation is the identity rather than anything read off it.
|
|
69
|
+
*
|
|
70
|
+
* @param {ClothInstance} instance
|
|
71
|
+
* @returns {void}
|
|
72
|
+
*/
|
|
73
|
+
export function cloth_reconstruct_pose(instance) {
|
|
74
|
+
const node_count = instance.node_count;
|
|
75
|
+
|
|
76
|
+
const state = instance.state;
|
|
77
|
+
const particle_of_node = instance.particle_of_node;
|
|
78
|
+
|
|
79
|
+
const blended = instance.blended_position;
|
|
80
|
+
const animated = instance.animated_position;
|
|
81
|
+
|
|
82
|
+
let blend = instance.cloth.blend;
|
|
83
|
+
|
|
84
|
+
if (blend < 0) {
|
|
85
|
+
blend = 0;
|
|
86
|
+
} else if (blend > 1) {
|
|
87
|
+
blend = 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const position = state.position;
|
|
91
|
+
|
|
92
|
+
for (let node = 0; node < node_count; node++) {
|
|
93
|
+
const p = particle_of_node[node] * 3;
|
|
94
|
+
const n = node * 3;
|
|
95
|
+
|
|
96
|
+
blended[n] = animated[n] + blend * (position[p] - animated[n]);
|
|
97
|
+
blended[n + 1] = animated[n + 1] + blend * (position[p + 1] - animated[n + 1]);
|
|
98
|
+
blended[n + 2] = animated[n + 2] + blend * (position[p + 2] - animated[n + 2]);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const parent = instance.node_parent;
|
|
102
|
+
const rotation = instance.animated_rotation;
|
|
103
|
+
|
|
104
|
+
const reconstructed = instance.blended_rotation;
|
|
105
|
+
|
|
106
|
+
reconstructed[0] = 0;
|
|
107
|
+
reconstructed[1] = 0;
|
|
108
|
+
reconstructed[2] = 0;
|
|
109
|
+
reconstructed[3] = 1;
|
|
110
|
+
|
|
111
|
+
for (let node = 1; node < node_count; node++) {
|
|
112
|
+
const has_parent_swing = link_swing(instance, parent[node], node, SWING_PARENT);
|
|
113
|
+
const has_child_swing = children_swing(instance, node, SWING_CHILD);
|
|
114
|
+
|
|
115
|
+
let swing = SWING_OUT;
|
|
116
|
+
|
|
117
|
+
if (has_parent_swing && has_child_swing) {
|
|
118
|
+
quat3_nlerp(
|
|
119
|
+
SWING, SWING_OUT,
|
|
120
|
+
SWING[SWING_PARENT], SWING[SWING_PARENT + 1], SWING[SWING_PARENT + 2], SWING[SWING_PARENT + 3],
|
|
121
|
+
SWING[SWING_CHILD], SWING[SWING_CHILD + 1], SWING[SWING_CHILD + 2], SWING[SWING_CHILD + 3],
|
|
122
|
+
0.5
|
|
123
|
+
);
|
|
124
|
+
} else if (has_child_swing) {
|
|
125
|
+
swing = SWING_CHILD;
|
|
126
|
+
} else {
|
|
127
|
+
// A leaf, or a link so short its direction is meaningless — in
|
|
128
|
+
// which case `link_swing` left the identity there.
|
|
129
|
+
swing = SWING_PARENT;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Animated orientation first, then the swing: the swing is expressed in
|
|
133
|
+
// the cloth's local frame.
|
|
134
|
+
quat3_multiply(
|
|
135
|
+
reconstructed, node * 4,
|
|
136
|
+
SWING[swing], SWING[swing + 1], SWING[swing + 2], SWING[swing + 3],
|
|
137
|
+
rotation[node * 4], rotation[node * 4 + 1], rotation[node * 4 + 2], rotation[node * 4 + 3]
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Swing of the link from `from` to `to`, into `SWING` at `out`.
|
|
144
|
+
*
|
|
145
|
+
* @param {ClothInstance} instance
|
|
146
|
+
* @param {number} from node
|
|
147
|
+
* @param {number} to node
|
|
148
|
+
* @param {number} out
|
|
149
|
+
* @returns {boolean} false when the link is too short to carry a direction, in
|
|
150
|
+
* which case the identity was written
|
|
151
|
+
* @private
|
|
152
|
+
*/
|
|
153
|
+
function link_swing(instance, from, to, out) {
|
|
154
|
+
const animated = instance.animated_position;
|
|
155
|
+
const blended = instance.blended_position;
|
|
156
|
+
|
|
157
|
+
const a = from * 3;
|
|
158
|
+
const b = to * 3;
|
|
159
|
+
|
|
160
|
+
const has_animated = unit(DIRECTION, 0,
|
|
161
|
+
animated[b] - animated[a], animated[b + 1] - animated[a + 1], animated[b + 2] - animated[a + 2]);
|
|
162
|
+
|
|
163
|
+
const has_blended = unit(DIRECTION, 3,
|
|
164
|
+
blended[b] - blended[a], blended[b + 1] - blended[a + 1], blended[b + 2] - blended[a + 2]);
|
|
165
|
+
|
|
166
|
+
if (!has_animated || !has_blended) {
|
|
167
|
+
identity(out);
|
|
168
|
+
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
quat3_shortest_arc(
|
|
173
|
+
SWING, out,
|
|
174
|
+
DIRECTION[0], DIRECTION[1], DIRECTION[2],
|
|
175
|
+
DIRECTION[3], DIRECTION[4], DIRECTION[5]
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Swing of a node's outgoing links, averaged over its simulated children.
|
|
183
|
+
*
|
|
184
|
+
* The average is over **unit** directions rather than over child positions, so
|
|
185
|
+
* a fork whose two branches are of different lengths is not dominated by the
|
|
186
|
+
* longer one.
|
|
187
|
+
*
|
|
188
|
+
* @param {ClothInstance} instance
|
|
189
|
+
* @param {number} node
|
|
190
|
+
* @param {number} out
|
|
191
|
+
* @returns {boolean}
|
|
192
|
+
* @private
|
|
193
|
+
*/
|
|
194
|
+
function children_swing(instance, node, out) {
|
|
195
|
+
const start = instance.node_child_offset[node];
|
|
196
|
+
const end = instance.node_child_offset[node + 1];
|
|
197
|
+
|
|
198
|
+
if (start === end) {
|
|
199
|
+
identity(out);
|
|
200
|
+
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const animated = instance.animated_position;
|
|
205
|
+
const blended = instance.blended_position;
|
|
206
|
+
const child = instance.node_child;
|
|
207
|
+
|
|
208
|
+
const a = node * 3;
|
|
209
|
+
|
|
210
|
+
let anim_x = 0, anim_y = 0, anim_z = 0;
|
|
211
|
+
let sim_x = 0, sim_y = 0, sim_z = 0;
|
|
212
|
+
|
|
213
|
+
for (let i = start; i < end; i++) {
|
|
214
|
+
const b = child[i] * 3;
|
|
215
|
+
|
|
216
|
+
if (unit(DIRECTION, 6,
|
|
217
|
+
animated[b] - animated[a], animated[b + 1] - animated[a + 1], animated[b + 2] - animated[a + 2])) {
|
|
218
|
+
anim_x += DIRECTION[6];
|
|
219
|
+
anim_y += DIRECTION[7];
|
|
220
|
+
anim_z += DIRECTION[8];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (unit(DIRECTION, 9,
|
|
224
|
+
blended[b] - blended[a], blended[b + 1] - blended[a + 1], blended[b + 2] - blended[a + 2])) {
|
|
225
|
+
sim_x += DIRECTION[9];
|
|
226
|
+
sim_y += DIRECTION[10];
|
|
227
|
+
sim_z += DIRECTION[11];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const has_animated = unit(DIRECTION, 0, anim_x, anim_y, anim_z);
|
|
232
|
+
const has_blended = unit(DIRECTION, 3, sim_x, sim_y, sim_z);
|
|
233
|
+
|
|
234
|
+
if (!has_animated || !has_blended) {
|
|
235
|
+
// Branches that cancel — a node with two children pointing opposite
|
|
236
|
+
// ways has no outgoing direction to speak of, and the parent link is a
|
|
237
|
+
// better answer than an arbitrary one.
|
|
238
|
+
identity(out);
|
|
239
|
+
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
quat3_shortest_arc(
|
|
244
|
+
SWING, out,
|
|
245
|
+
DIRECTION[0], DIRECTION[1], DIRECTION[2],
|
|
246
|
+
DIRECTION[3], DIRECTION[4], DIRECTION[5]
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Normalise into `out`, reporting whether there was a direction to find.
|
|
254
|
+
*
|
|
255
|
+
* @param {Float64Array} out
|
|
256
|
+
* @param {number} offset
|
|
257
|
+
* @param {number} x
|
|
258
|
+
* @param {number} y
|
|
259
|
+
* @param {number} z
|
|
260
|
+
* @returns {boolean}
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
263
|
+
function unit(out, offset, x, y, z) {
|
|
264
|
+
const length_squared = x * x + y * y + z * z;
|
|
265
|
+
|
|
266
|
+
if (length_squared < 1e-24) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const inverse = 1 / Math.sqrt(length_squared);
|
|
271
|
+
|
|
272
|
+
out[offset] = x * inverse;
|
|
273
|
+
out[offset + 1] = y * inverse;
|
|
274
|
+
out[offset + 2] = z * inverse;
|
|
275
|
+
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* @param {number} offset
|
|
281
|
+
* @private
|
|
282
|
+
*/
|
|
283
|
+
function identity(offset) {
|
|
284
|
+
SWING[offset] = 0;
|
|
285
|
+
SWING[offset + 1] = 0;
|
|
286
|
+
SWING[offset + 2] = 0;
|
|
287
|
+
SWING[offset + 3] = 1;
|
|
288
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Seeding a cloth from a skinned model's joints — §11.2
|
|
3
|
+
*
|
|
4
|
+
* One particle per joint the proxy names, with the anchor as the fixed set, and
|
|
5
|
+
* everything after that is `cloth_build_rows.js` — the same rows, the same
|
|
6
|
+
* geodesics, the same leashes the entity path gets. §11 says "the solver is
|
|
7
|
+
* identical either way; only seeding and write-back differ", and this file plus
|
|
8
|
+
* `cloth_write_back_rig.js` is the whole of the difference.
|
|
9
|
+
*
|
|
10
|
+
* ## Cloth takes authority, and that is a real claim
|
|
11
|
+
*
|
|
12
|
+
* §11.2 says the writable handle is "the joint's `Node3D.transform_local` — the
|
|
13
|
+
* same handle the animation systems write". **The animation systems do not
|
|
14
|
+
* write it.** `TransformAuthority` is explicit: a node a clip drives is
|
|
15
|
+
* `GPU`, and "the CPU allocates and seeds the row, then never writes to it
|
|
16
|
+
* again, so the node's own `transform_local` stops describing it and should not
|
|
17
|
+
* be read as if it did". Cloth writing `transform_local` on such a node would
|
|
18
|
+
* be writing to something nothing reads.
|
|
19
|
+
*
|
|
20
|
+
* So the seed **claims** `TransformAuthority.CPU` on every joint it drives. The
|
|
21
|
+
* consequence is stated rather than hidden: a joint cloth simulates stops being
|
|
22
|
+
* animatable by a clip, because two writers of one row is the race the authority
|
|
23
|
+
* enum exists to prevent. That is the right trade for a cape — the whole point
|
|
24
|
+
* of simulating it is that nobody keyframes it — and it is an authoring error
|
|
25
|
+
* for a garment whose joints are also keyed, which is why the seed says so.
|
|
26
|
+
*
|
|
27
|
+
* ## The animated pose is constant, exactly as it is for a rope
|
|
28
|
+
*
|
|
29
|
+
* §11.1 says a subtree's authored pose is rigid relative to its anchor, so in
|
|
30
|
+
* the anchor's own frame it does not move, and then says "a subtree whose links
|
|
31
|
+
* are themselves animated is not an M1 case — that is the rig path, where the
|
|
32
|
+
* animated pose comes from the skeleton and is live".
|
|
33
|
+
*
|
|
34
|
+
* For a **rigged** garment it is not live either, and the reason is the
|
|
35
|
+
* authority claim above: cloth owns those joints, so nothing else poses them,
|
|
36
|
+
* so their authored pose is the proxy's baked bind pose — constant in the
|
|
37
|
+
* anchor's frame, exactly as a rope's is. What moves is the anchor, and the
|
|
38
|
+
* anchor is a joint of the character's own animated skeleton.
|
|
39
|
+
*
|
|
40
|
+
* The live case is the **unrigged** path, where the animated targets are mesh
|
|
41
|
+
* vertices skinned to the character's skeleton by
|
|
42
|
+
* `mesh_apply_skeletal_vertex_skinning` and genuinely move under the animation.
|
|
43
|
+
* That path is not in M3.
|
|
44
|
+
*
|
|
45
|
+
* @author Alex Goldring
|
|
46
|
+
* @copyright Company Named Limited (c) 2026
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* Seed `instance` from a proxy and the joints of a skin.
|
|
50
|
+
*
|
|
51
|
+
* @param {ClothInstance} instance seeded in place
|
|
52
|
+
* @param {ClothProxy} proxy
|
|
53
|
+
* @param {Node3D[]} joints the skin's joints, in the order the proxy indexes
|
|
54
|
+
* @param {number} dt fixed step, seconds
|
|
55
|
+
* @returns {void}
|
|
56
|
+
*/
|
|
57
|
+
export function cloth_seed_rig(instance: ClothInstance, proxy: ClothProxy, joints: Node3D[], dt: number): void;
|
|
58
|
+
//# sourceMappingURL=cloth_seed_rig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloth_seed_rig.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/ecs/cloth_seed_rig.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH;;;;;;;;GAQG;AACH,mFAJW,QAAQ,MACR,MAAM,GACJ,IAAI,CA6DhB"}
|