@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,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # The built artefact a `ClothRig` points at
|
|
3
|
+
*
|
|
4
|
+
* Shared, immutable, and produced once at import. `ClothRig#proxy` holds one of
|
|
5
|
+
* these the way `Collider#shape` holds an `AbstractShape3D` and `ParticleEffect`
|
|
6
|
+
* holds a `ParticleProgram`: the component serialises the proxy's *identity*,
|
|
7
|
+
* and the asset pipeline wires the object up (§3.2).
|
|
8
|
+
*
|
|
9
|
+
* ## Joints by index, resolved once
|
|
10
|
+
*
|
|
11
|
+
* Every field below is an integer or a float. **No names survive into the
|
|
12
|
+
* runtime**, and that is §3.2's central commitment: a joint is a `Node3D` inside
|
|
13
|
+
* a `SceneBundleInstance` rather than an entity, so an `EntityReference` to one
|
|
14
|
+
* is impossible by construction, and reintroducing strings at runtime to work
|
|
15
|
+
* around that would be the wrong answer. {@link joint} holds indices into
|
|
16
|
+
* `Skin#joints`, resolved at build time from `SceneBundleInstance#nodes`.
|
|
17
|
+
*
|
|
18
|
+
* {@link joint_name} is the exception and it is build-time provenance: it is
|
|
19
|
+
* what a diagnostic prints when a proxy does not fit the model it was pointed
|
|
20
|
+
* at, and nothing on the step path reads it.
|
|
21
|
+
*
|
|
22
|
+
* ## The rigged form, which is the whole of M3
|
|
23
|
+
*
|
|
24
|
+
* §11.2 has two cases and they differ only in where the joints and the weights
|
|
25
|
+
* came from. **A rigged garment brings both**: an artist made 8–20 cape joints
|
|
26
|
+
* and skinned the cape to them, so the proxy is thin — joint indices, the
|
|
27
|
+
* topology connecting them, the bind pose, and `d_geo`. There is no binding
|
|
28
|
+
* step and no generated geometry, because the artist's skin *is* the relation.
|
|
29
|
+
*
|
|
30
|
+
* The unrigged case generates a joint set and a skin for a garment that has
|
|
31
|
+
* neither, and its extra data — the render mesh's generated weights and
|
|
32
|
+
* inverse-bind matrices — is not in this class yet. §11.3 step 9 and §18's open
|
|
33
|
+
* joint-budget question are what would add it.
|
|
34
|
+
*
|
|
35
|
+
* ## The bind pose is baked, not read
|
|
36
|
+
*
|
|
37
|
+
* {@link rest_position} and {@link rest_rotation} are the joints' **local**
|
|
38
|
+
* transforms at bind time, carried in the proxy rather than read from the
|
|
39
|
+
* instance at seed. Reading them from the instance works exactly once: cloth
|
|
40
|
+
* takes ownership of `Node3D.transform_local` the moment it starts writing, so
|
|
41
|
+
* a re-seed of a live garment would read the shape the solver left behind and
|
|
42
|
+
* call it the authored pose. M1 solved the same problem for the entity path with
|
|
43
|
+
* a per-seed capture (`remember_rest_pose`); a proxy can do better, because the
|
|
44
|
+
* bind pose is build data and does not have to be remembered at all.
|
|
45
|
+
*
|
|
46
|
+
* @author Alex Goldring
|
|
47
|
+
* @copyright Company Named Limited (c) 2026
|
|
48
|
+
*/
|
|
49
|
+
export class ClothProxy {
|
|
50
|
+
/**
|
|
51
|
+
* @param {object} description
|
|
52
|
+
* @param {string} [description.name]
|
|
53
|
+
* @param {Int32Array|number[]} description.joint
|
|
54
|
+
* @param {Int32Array|number[]} description.joint_parent
|
|
55
|
+
* @param {number} description.anchor
|
|
56
|
+
* @param {Float32Array|number[]} description.rest_position
|
|
57
|
+
* @param {Float32Array|number[]} description.rest_rotation
|
|
58
|
+
* @param {string[]} [description.joint_name]
|
|
59
|
+
* @returns {ClothProxy}
|
|
60
|
+
*/
|
|
61
|
+
static from({ name, joint, joint_parent, anchor, rest_position, rest_rotation, joint_name }: {
|
|
62
|
+
name?: string;
|
|
63
|
+
joint: Int32Array | number[];
|
|
64
|
+
joint_parent: Int32Array | number[];
|
|
65
|
+
anchor: number;
|
|
66
|
+
rest_position: Float32Array | number[];
|
|
67
|
+
rest_rotation: Float32Array | number[];
|
|
68
|
+
joint_name?: string[];
|
|
69
|
+
}): ClothProxy;
|
|
70
|
+
/**
|
|
71
|
+
* Name, for diagnostics and for a tool listing the proxies an asset carries.
|
|
72
|
+
* @type {string}
|
|
73
|
+
*/
|
|
74
|
+
name: string;
|
|
75
|
+
/**
|
|
76
|
+
* How many joints this proxy simulates. The anchor is **not** one of them.
|
|
77
|
+
* @type {number}
|
|
78
|
+
*/
|
|
79
|
+
joint_count: number;
|
|
80
|
+
/**
|
|
81
|
+
* Index into `Skin#joints` for each simulated joint.
|
|
82
|
+
* @type {Int32Array}
|
|
83
|
+
*/
|
|
84
|
+
joint: Int32Array;
|
|
85
|
+
/**
|
|
86
|
+
* Parent of each simulated joint, as an index into this proxy's own joint
|
|
87
|
+
* list, or `-1` for a joint whose parent is the anchor.
|
|
88
|
+
*
|
|
89
|
+
* A proxy's joints are stored **parents before children**, so one forward
|
|
90
|
+
* pass composes the whole chain — the same ordering `cloth_seed_subtree`
|
|
91
|
+
* gets from a breadth-first walk, and for the same reason.
|
|
92
|
+
* @type {Int32Array}
|
|
93
|
+
*/
|
|
94
|
+
joint_parent: Int32Array;
|
|
95
|
+
/**
|
|
96
|
+
* Index into `Skin#joints` of the joint the garment hangs from.
|
|
97
|
+
*
|
|
98
|
+
* It is not simulated, it is the cloth's local frame, and its `d_geo` is
|
|
99
|
+
* zero — which is what makes §3.4's derived quantities collapse onto it
|
|
100
|
+
* correctly without a second mechanism saying "this one is pinned".
|
|
101
|
+
*
|
|
102
|
+
* For a rigged garment the fixed set *is* the anchor, and it falls out of
|
|
103
|
+
* the topology rather than out of skin weights: a joint whose parent is
|
|
104
|
+
* outside the proxy is a joint the garment hangs from. §11.3's step 5 —
|
|
105
|
+
* "particles whose skin weights are dominated by joints outside the
|
|
106
|
+
* garment's own joint set are pinned" — is the **unrigged** rule, where the
|
|
107
|
+
* particles are mesh vertices and there is no joint tree to read.
|
|
108
|
+
* @type {number}
|
|
109
|
+
*/
|
|
110
|
+
anchor: number;
|
|
111
|
+
/**
|
|
112
|
+
* Each joint's bind-pose local translation, 3 per joint.
|
|
113
|
+
* @type {Float32Array}
|
|
114
|
+
*/
|
|
115
|
+
rest_position: Float32Array;
|
|
116
|
+
/**
|
|
117
|
+
* Each joint's bind-pose local rotation, 4 per joint.
|
|
118
|
+
* @type {Float32Array}
|
|
119
|
+
*/
|
|
120
|
+
rest_rotation: Float32Array;
|
|
121
|
+
/**
|
|
122
|
+
* Names, in {@link joint} order, then the anchor's last. Build-time
|
|
123
|
+
* provenance; nothing on the step path reads it.
|
|
124
|
+
* @type {string[]}
|
|
125
|
+
*/
|
|
126
|
+
joint_name: string[];
|
|
127
|
+
/**
|
|
128
|
+
* Whether this proxy can address the skin it is about to be used with.
|
|
129
|
+
*
|
|
130
|
+
* A proxy is built against one model and a `ClothRig` points at whichever
|
|
131
|
+
* one the entity is showing, so the two can disagree — a model swap, an
|
|
132
|
+
* asset rebuilt with a joint removed, a proxy pointed at the wrong skin
|
|
133
|
+
* ordinal. Every one of those is an authoring mistake rather than a runtime
|
|
134
|
+
* condition, and this is what turns it into a message naming the joint
|
|
135
|
+
* instead of a garment simulating somebody's spine.
|
|
136
|
+
*
|
|
137
|
+
* @param {Skin} skin
|
|
138
|
+
* @returns {string} empty when the proxy fits, otherwise what is wrong
|
|
139
|
+
*/
|
|
140
|
+
checkAgainst(skin: Skin): string;
|
|
141
|
+
/**
|
|
142
|
+
* @readonly
|
|
143
|
+
* @type {boolean}
|
|
144
|
+
*/
|
|
145
|
+
readonly isClothProxy: boolean;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=ClothProxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClothProxy.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/ClothProxy.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH;IAmEI;;;;;;;;;;OAUG;IACH;QATgC,IAAI,GAAzB,MAAM;QAC2B,KAAK,EAAtC,UAAU,GAAC,MAAM,EAAE;QACc,YAAY,EAA7C,UAAU,GAAC,MAAM,EAAE;QACC,MAAM,EAA1B,MAAM;QAC6B,aAAa,EAAhD,YAAY,GAAC,MAAM,EAAE;QACc,aAAa,EAAhD,YAAY,GAAC,MAAM,EAAE;QACE,UAAU,GAAjC,MAAM,EAAE;QACN,UAAU,CAuCtB;IAjHD;;;OAGG;IACH,MAFU,MAAM,CAEN;IAEV;;;OAGG;IACH,aAFU,MAAM,CAEA;IAEhB;;;OAGG;IACH,OAFU,UAAU,CAEP;IAEb;;;;;;;;OAQG;IACH,cAFU,UAAU,CAEA;IAEpB;;;;;;;;;;;;;;OAcG;IACH,QAFU,MAAM,CAEJ;IAEZ;;;OAGG;IACH,eAFU,YAAY,CAED;IAErB;;;OAGG;IACH,eAFU,YAAY,CAED;IAErB;;;;OAIG;IACH,YAFU,MAAM,EAAE,CAEF;IAoDhB;;;;;;;;;;;;OAYG;IACH,0BAFa,MAAM,CAqBlB;IAGL;;;OAGG;IACH,uBAFU,OAAO,CAEgB;CANhC"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* # The built artefact a `ClothRig` points at
|
|
5
|
+
*
|
|
6
|
+
* Shared, immutable, and produced once at import. `ClothRig#proxy` holds one of
|
|
7
|
+
* these the way `Collider#shape` holds an `AbstractShape3D` and `ParticleEffect`
|
|
8
|
+
* holds a `ParticleProgram`: the component serialises the proxy's *identity*,
|
|
9
|
+
* and the asset pipeline wires the object up (§3.2).
|
|
10
|
+
*
|
|
11
|
+
* ## Joints by index, resolved once
|
|
12
|
+
*
|
|
13
|
+
* Every field below is an integer or a float. **No names survive into the
|
|
14
|
+
* runtime**, and that is §3.2's central commitment: a joint is a `Node3D` inside
|
|
15
|
+
* a `SceneBundleInstance` rather than an entity, so an `EntityReference` to one
|
|
16
|
+
* is impossible by construction, and reintroducing strings at runtime to work
|
|
17
|
+
* around that would be the wrong answer. {@link joint} holds indices into
|
|
18
|
+
* `Skin#joints`, resolved at build time from `SceneBundleInstance#nodes`.
|
|
19
|
+
*
|
|
20
|
+
* {@link joint_name} is the exception and it is build-time provenance: it is
|
|
21
|
+
* what a diagnostic prints when a proxy does not fit the model it was pointed
|
|
22
|
+
* at, and nothing on the step path reads it.
|
|
23
|
+
*
|
|
24
|
+
* ## The rigged form, which is the whole of M3
|
|
25
|
+
*
|
|
26
|
+
* §11.2 has two cases and they differ only in where the joints and the weights
|
|
27
|
+
* came from. **A rigged garment brings both**: an artist made 8–20 cape joints
|
|
28
|
+
* and skinned the cape to them, so the proxy is thin — joint indices, the
|
|
29
|
+
* topology connecting them, the bind pose, and `d_geo`. There is no binding
|
|
30
|
+
* step and no generated geometry, because the artist's skin *is* the relation.
|
|
31
|
+
*
|
|
32
|
+
* The unrigged case generates a joint set and a skin for a garment that has
|
|
33
|
+
* neither, and its extra data — the render mesh's generated weights and
|
|
34
|
+
* inverse-bind matrices — is not in this class yet. §11.3 step 9 and §18's open
|
|
35
|
+
* joint-budget question are what would add it.
|
|
36
|
+
*
|
|
37
|
+
* ## The bind pose is baked, not read
|
|
38
|
+
*
|
|
39
|
+
* {@link rest_position} and {@link rest_rotation} are the joints' **local**
|
|
40
|
+
* transforms at bind time, carried in the proxy rather than read from the
|
|
41
|
+
* instance at seed. Reading them from the instance works exactly once: cloth
|
|
42
|
+
* takes ownership of `Node3D.transform_local` the moment it starts writing, so
|
|
43
|
+
* a re-seed of a live garment would read the shape the solver left behind and
|
|
44
|
+
* call it the authored pose. M1 solved the same problem for the entity path with
|
|
45
|
+
* a per-seed capture (`remember_rest_pose`); a proxy can do better, because the
|
|
46
|
+
* bind pose is build data and does not have to be remembered at all.
|
|
47
|
+
*
|
|
48
|
+
* @author Alex Goldring
|
|
49
|
+
* @copyright Company Named Limited (c) 2026
|
|
50
|
+
*/
|
|
51
|
+
export class ClothProxy {
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Name, for diagnostics and for a tool listing the proxies an asset carries.
|
|
55
|
+
* @type {string}
|
|
56
|
+
*/
|
|
57
|
+
name = "";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* How many joints this proxy simulates. The anchor is **not** one of them.
|
|
61
|
+
* @type {number}
|
|
62
|
+
*/
|
|
63
|
+
joint_count = 0;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Index into `Skin#joints` for each simulated joint.
|
|
67
|
+
* @type {Int32Array}
|
|
68
|
+
*/
|
|
69
|
+
joint = null;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parent of each simulated joint, as an index into this proxy's own joint
|
|
73
|
+
* list, or `-1` for a joint whose parent is the anchor.
|
|
74
|
+
*
|
|
75
|
+
* A proxy's joints are stored **parents before children**, so one forward
|
|
76
|
+
* pass composes the whole chain — the same ordering `cloth_seed_subtree`
|
|
77
|
+
* gets from a breadth-first walk, and for the same reason.
|
|
78
|
+
* @type {Int32Array}
|
|
79
|
+
*/
|
|
80
|
+
joint_parent = null;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Index into `Skin#joints` of the joint the garment hangs from.
|
|
84
|
+
*
|
|
85
|
+
* It is not simulated, it is the cloth's local frame, and its `d_geo` is
|
|
86
|
+
* zero — which is what makes §3.4's derived quantities collapse onto it
|
|
87
|
+
* correctly without a second mechanism saying "this one is pinned".
|
|
88
|
+
*
|
|
89
|
+
* For a rigged garment the fixed set *is* the anchor, and it falls out of
|
|
90
|
+
* the topology rather than out of skin weights: a joint whose parent is
|
|
91
|
+
* outside the proxy is a joint the garment hangs from. §11.3's step 5 —
|
|
92
|
+
* "particles whose skin weights are dominated by joints outside the
|
|
93
|
+
* garment's own joint set are pinned" — is the **unrigged** rule, where the
|
|
94
|
+
* particles are mesh vertices and there is no joint tree to read.
|
|
95
|
+
* @type {number}
|
|
96
|
+
*/
|
|
97
|
+
anchor = -1;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Each joint's bind-pose local translation, 3 per joint.
|
|
101
|
+
* @type {Float32Array}
|
|
102
|
+
*/
|
|
103
|
+
rest_position = null;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Each joint's bind-pose local rotation, 4 per joint.
|
|
107
|
+
* @type {Float32Array}
|
|
108
|
+
*/
|
|
109
|
+
rest_rotation = null;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Names, in {@link joint} order, then the anchor's last. Build-time
|
|
113
|
+
* provenance; nothing on the step path reads it.
|
|
114
|
+
* @type {string[]}
|
|
115
|
+
*/
|
|
116
|
+
joint_name = [];
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {object} description
|
|
120
|
+
* @param {string} [description.name]
|
|
121
|
+
* @param {Int32Array|number[]} description.joint
|
|
122
|
+
* @param {Int32Array|number[]} description.joint_parent
|
|
123
|
+
* @param {number} description.anchor
|
|
124
|
+
* @param {Float32Array|number[]} description.rest_position
|
|
125
|
+
* @param {Float32Array|number[]} description.rest_rotation
|
|
126
|
+
* @param {string[]} [description.joint_name]
|
|
127
|
+
* @returns {ClothProxy}
|
|
128
|
+
*/
|
|
129
|
+
static from({
|
|
130
|
+
name = "",
|
|
131
|
+
joint,
|
|
132
|
+
joint_parent,
|
|
133
|
+
anchor,
|
|
134
|
+
rest_position,
|
|
135
|
+
rest_rotation,
|
|
136
|
+
joint_name = []
|
|
137
|
+
}) {
|
|
138
|
+
const joint_count = joint.length;
|
|
139
|
+
|
|
140
|
+
assert.equal(joint_parent.length, joint_count, 'joint_parent.length');
|
|
141
|
+
assert.equal(rest_position.length, joint_count * 3, 'rest_position.length');
|
|
142
|
+
assert.equal(rest_rotation.length, joint_count * 4, 'rest_rotation.length');
|
|
143
|
+
assert.isNonNegativeInteger(anchor, 'anchor');
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < joint_count; i++) {
|
|
146
|
+
// Parents before children: the composition down the chain is one
|
|
147
|
+
// forward pass and there is nowhere for a cycle to hide.
|
|
148
|
+
assert.ok(
|
|
149
|
+
joint_parent[i] < i,
|
|
150
|
+
`ClothProxy joint ${i} has parent ${joint_parent[i]}, which is not before it`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const r = new ClothProxy();
|
|
155
|
+
|
|
156
|
+
r.name = name;
|
|
157
|
+
r.joint_count = joint_count;
|
|
158
|
+
r.joint = Int32Array.from(joint);
|
|
159
|
+
r.joint_parent = Int32Array.from(joint_parent);
|
|
160
|
+
r.anchor = anchor;
|
|
161
|
+
r.rest_position = Float32Array.from(rest_position);
|
|
162
|
+
r.rest_rotation = Float32Array.from(rest_rotation);
|
|
163
|
+
r.joint_name = joint_name.slice();
|
|
164
|
+
|
|
165
|
+
return r;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Whether this proxy can address the skin it is about to be used with.
|
|
170
|
+
*
|
|
171
|
+
* A proxy is built against one model and a `ClothRig` points at whichever
|
|
172
|
+
* one the entity is showing, so the two can disagree — a model swap, an
|
|
173
|
+
* asset rebuilt with a joint removed, a proxy pointed at the wrong skin
|
|
174
|
+
* ordinal. Every one of those is an authoring mistake rather than a runtime
|
|
175
|
+
* condition, and this is what turns it into a message naming the joint
|
|
176
|
+
* instead of a garment simulating somebody's spine.
|
|
177
|
+
*
|
|
178
|
+
* @param {Skin} skin
|
|
179
|
+
* @returns {string} empty when the proxy fits, otherwise what is wrong
|
|
180
|
+
*/
|
|
181
|
+
checkAgainst(skin) {
|
|
182
|
+
if (skin === undefined || skin === null) {
|
|
183
|
+
return `${this.name}: no skin`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const count = skin.joints.length;
|
|
187
|
+
|
|
188
|
+
if (this.anchor >= count) {
|
|
189
|
+
return `${this.name}: anchor is joint ${this.anchor} of a skin with ${count}`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (let i = 0; i < this.joint_count; i++) {
|
|
193
|
+
if (this.joint[i] >= count) {
|
|
194
|
+
return `${this.name}: joint ${i} (${this.joint_name[i] ?? '?'})`
|
|
195
|
+
+ ` is index ${this.joint[i]} of a skin with ${count}`;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return "";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @readonly
|
|
205
|
+
* @type {boolean}
|
|
206
|
+
*/
|
|
207
|
+
ClothProxy.prototype.isClothProxy = true;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Building a proxy for a garment that is already rigged
|
|
3
|
+
*
|
|
4
|
+
* §11.3 lists ten steps and says that for a rigged garment "only steps 5–8 run,
|
|
5
|
+
* over the joint graph rather than a mesh". This is those steps: derive the
|
|
6
|
+
* fixed set, bake the bind pose, resolve names to indices, and validate. Steps
|
|
7
|
+
* 1–4 are mesh work a rigged garment does not need — the artist's joints *are*
|
|
8
|
+
* the particle set and the artist's skin *is* the binding — and steps 9 and 10's
|
|
9
|
+
* mesh half belong to the unrigged path.
|
|
10
|
+
*
|
|
11
|
+
* The colouring step (7) is absent for a reason rather than an omission: the
|
|
12
|
+
* cloth's own row builder colours the particle graph inside
|
|
13
|
+
* `ClothState.from`, and it does that for the entity path too. Baking a
|
|
14
|
+
* permutation into the proxy would be a second answer to a question that
|
|
15
|
+
* already has one, and it would have to agree with `cloth_color_particles`
|
|
16
|
+
* exactly or the rows would name the wrong particles.
|
|
17
|
+
*
|
|
18
|
+
* ## The fixed set falls out of the topology
|
|
19
|
+
*
|
|
20
|
+
* A joint whose parent is outside the named set is a joint the garment hangs
|
|
21
|
+
* from, and **every one of them must hang from the same bone** — that bone is
|
|
22
|
+
* the anchor. §11.3 step 5 derives the fixed set from *skin weights* instead,
|
|
23
|
+
* which is the right rule for the unrigged path, where the particles are mesh
|
|
24
|
+
* vertices and there is no joint tree to read. For a rigged garment the tree is
|
|
25
|
+
* the answer and the weights are not needed.
|
|
26
|
+
*
|
|
27
|
+
* Several chains from one bone are one garment and are the point: §3.1's "put
|
|
28
|
+
* `Cloth` on a node with several chains under it and you get all of them in one
|
|
29
|
+
* coupled solve" is exactly a cape's four strips off one shoulder. Chains from
|
|
30
|
+
* *different* bones are refused, because there is then no single frame to
|
|
31
|
+
* simulate in and no single fixed set — that is two garments, and nothing stops
|
|
32
|
+
* a caller building two proxies.
|
|
33
|
+
*
|
|
34
|
+
* @author Alex Goldring
|
|
35
|
+
* @copyright Company Named Limited (c) 2026
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {object} ClothProxyBuildResult
|
|
39
|
+
* @property {ClothProxy|null} proxy `null` when the build refused
|
|
40
|
+
* @property {string} error empty when it did not
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Build a proxy from the joints of a skin, named.
|
|
44
|
+
*
|
|
45
|
+
* The names are the only place a name appears anywhere in the system (§11.3
|
|
46
|
+
* step 8) and they do not survive: what comes back holds indices into
|
|
47
|
+
* `skin.joints`.
|
|
48
|
+
*
|
|
49
|
+
* @param {Skin} skin the instance's skin, or the asset's — the joint *order* is
|
|
50
|
+
* what is read, and instantiation preserves it
|
|
51
|
+
* @param {string[]} joint_names the garment's own joints, in any order
|
|
52
|
+
* @param {object} [options]
|
|
53
|
+
* @param {string} [options.name]
|
|
54
|
+
* @returns {ClothProxyBuildResult}
|
|
55
|
+
*/
|
|
56
|
+
export function cloth_proxy_from_joints(skin: Skin, joint_names: string[], { name }?: {
|
|
57
|
+
name?: string;
|
|
58
|
+
}): ClothProxyBuildResult;
|
|
59
|
+
export type ClothProxyBuildResult = {
|
|
60
|
+
/**
|
|
61
|
+
* `null` when the build refused
|
|
62
|
+
*/
|
|
63
|
+
proxy: ClothProxy | null;
|
|
64
|
+
/**
|
|
65
|
+
* empty when it did not
|
|
66
|
+
*/
|
|
67
|
+
error: string;
|
|
68
|
+
};
|
|
69
|
+
import { ClothProxy } from "./ClothProxy.js";
|
|
70
|
+
//# sourceMappingURL=cloth_proxy_from_joints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloth_proxy_from_joints.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/cloth/build/cloth_proxy_from_joints.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AACH,iEALW,MAAM,EAAE;IAES,IAAI,GAArB,MAAM;IACJ,qBAAqB,CAyLjC;;;;;WAzMa,UAAU,GAAC,IAAI;;;;WACf,MAAM;;2BA1CO,iBAAiB"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TRANSFORM64_ROTATION_OFFSET,
|
|
3
|
+
TRANSFORM64_TRANSLATION_OFFSET
|
|
4
|
+
} from "../../../ecs/transform/Transform64.js";
|
|
5
|
+
import { ClothProxy } from "./ClothProxy.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* # Building a proxy for a garment that is already rigged
|
|
9
|
+
*
|
|
10
|
+
* §11.3 lists ten steps and says that for a rigged garment "only steps 5–8 run,
|
|
11
|
+
* over the joint graph rather than a mesh". This is those steps: derive the
|
|
12
|
+
* fixed set, bake the bind pose, resolve names to indices, and validate. Steps
|
|
13
|
+
* 1–4 are mesh work a rigged garment does not need — the artist's joints *are*
|
|
14
|
+
* the particle set and the artist's skin *is* the binding — and steps 9 and 10's
|
|
15
|
+
* mesh half belong to the unrigged path.
|
|
16
|
+
*
|
|
17
|
+
* The colouring step (7) is absent for a reason rather than an omission: the
|
|
18
|
+
* cloth's own row builder colours the particle graph inside
|
|
19
|
+
* `ClothState.from`, and it does that for the entity path too. Baking a
|
|
20
|
+
* permutation into the proxy would be a second answer to a question that
|
|
21
|
+
* already has one, and it would have to agree with `cloth_color_particles`
|
|
22
|
+
* exactly or the rows would name the wrong particles.
|
|
23
|
+
*
|
|
24
|
+
* ## The fixed set falls out of the topology
|
|
25
|
+
*
|
|
26
|
+
* A joint whose parent is outside the named set is a joint the garment hangs
|
|
27
|
+
* from, and **every one of them must hang from the same bone** — that bone is
|
|
28
|
+
* the anchor. §11.3 step 5 derives the fixed set from *skin weights* instead,
|
|
29
|
+
* which is the right rule for the unrigged path, where the particles are mesh
|
|
30
|
+
* vertices and there is no joint tree to read. For a rigged garment the tree is
|
|
31
|
+
* the answer and the weights are not needed.
|
|
32
|
+
*
|
|
33
|
+
* Several chains from one bone are one garment and are the point: §3.1's "put
|
|
34
|
+
* `Cloth` on a node with several chains under it and you get all of them in one
|
|
35
|
+
* coupled solve" is exactly a cape's four strips off one shoulder. Chains from
|
|
36
|
+
* *different* bones are refused, because there is then no single frame to
|
|
37
|
+
* simulate in and no single fixed set — that is two garments, and nothing stops
|
|
38
|
+
* a caller building two proxies.
|
|
39
|
+
*
|
|
40
|
+
* @author Alex Goldring
|
|
41
|
+
* @copyright Company Named Limited (c) 2026
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {object} ClothProxyBuildResult
|
|
46
|
+
* @property {ClothProxy|null} proxy `null` when the build refused
|
|
47
|
+
* @property {string} error empty when it did not
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Build a proxy from the joints of a skin, named.
|
|
52
|
+
*
|
|
53
|
+
* The names are the only place a name appears anywhere in the system (§11.3
|
|
54
|
+
* step 8) and they do not survive: what comes back holds indices into
|
|
55
|
+
* `skin.joints`.
|
|
56
|
+
*
|
|
57
|
+
* @param {Skin} skin the instance's skin, or the asset's — the joint *order* is
|
|
58
|
+
* what is read, and instantiation preserves it
|
|
59
|
+
* @param {string[]} joint_names the garment's own joints, in any order
|
|
60
|
+
* @param {object} [options]
|
|
61
|
+
* @param {string} [options.name]
|
|
62
|
+
* @returns {ClothProxyBuildResult}
|
|
63
|
+
*/
|
|
64
|
+
export function cloth_proxy_from_joints(skin, joint_names, { name = "" } = {}) {
|
|
65
|
+
if (skin === undefined || skin === null) {
|
|
66
|
+
return refuse(`${name}: no skin`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const joints = skin.joints;
|
|
70
|
+
|
|
71
|
+
/** @type {Map<Node3D, number>} node → index in `skin.joints` */
|
|
72
|
+
const index_of = new Map();
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < joints.length; i++) {
|
|
75
|
+
index_of.set(joints[i], i);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @type {Map<string, Node3D>} */
|
|
79
|
+
const by_name = new Map();
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < joints.length; i++) {
|
|
82
|
+
const joint = joints[i];
|
|
83
|
+
|
|
84
|
+
if (joint.name !== "" && !by_name.has(joint.name)) {
|
|
85
|
+
by_name.set(joint.name, joint);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @type {Set<Node3D>} the garment's own joints */
|
|
90
|
+
const members = new Set();
|
|
91
|
+
|
|
92
|
+
for (const joint_name of joint_names) {
|
|
93
|
+
const node = by_name.get(joint_name);
|
|
94
|
+
|
|
95
|
+
if (node === undefined) {
|
|
96
|
+
return refuse(`${name}: the skin has no joint named "${joint_name}"`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (members.has(node)) {
|
|
100
|
+
return refuse(`${name}: "${joint_name}" is named twice`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
members.add(node);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (members.size === 0) {
|
|
107
|
+
return refuse(`${name}: no joints`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Roots: members whose parent is not a member. They all have to hang from
|
|
111
|
+
// the same bone, and that bone is the anchor.
|
|
112
|
+
/** @type {Node3D[]} */
|
|
113
|
+
const roots = [];
|
|
114
|
+
|
|
115
|
+
for (const node of members) {
|
|
116
|
+
if (node.parent === null || !members.has(node.parent)) {
|
|
117
|
+
roots.push(node);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const anchor_node = roots[0].parent;
|
|
122
|
+
|
|
123
|
+
if (anchor_node === null) {
|
|
124
|
+
return refuse(`${name}: "${roots[0].name}" has no parent, so the garment has nothing to hang from`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const root of roots) {
|
|
128
|
+
if (root.parent !== anchor_node) {
|
|
129
|
+
return refuse(
|
|
130
|
+
`${name}: "${roots[0].name}" hangs from "${anchor_node.name}" and "${root.name}" hangs`
|
|
131
|
+
+ ` from "${root.parent === null ? 'nothing' : root.parent.name}" — a garment hangs from one`
|
|
132
|
+
+ ` anchor, and chains from different bones are two garments`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const anchor = index_of.get(anchor_node);
|
|
138
|
+
|
|
139
|
+
if (anchor === undefined) {
|
|
140
|
+
return refuse(
|
|
141
|
+
`${name}: "${roots[0].name}" hangs from "${anchor_node.name}", which is not a joint of this skin`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Parents before children, so one forward pass composes the chain.
|
|
146
|
+
/** @type {Node3D[]} */
|
|
147
|
+
const ordered = [];
|
|
148
|
+
|
|
149
|
+
/** @type {Map<Node3D, number>} */
|
|
150
|
+
const position = new Map();
|
|
151
|
+
|
|
152
|
+
// Breadth-first from every root at once, which keeps parents before
|
|
153
|
+
// children across the whole forest rather than only within one chain.
|
|
154
|
+
const queue = roots.slice();
|
|
155
|
+
|
|
156
|
+
while (queue.length > 0) {
|
|
157
|
+
const node = queue.shift();
|
|
158
|
+
|
|
159
|
+
position.set(node, ordered.length);
|
|
160
|
+
ordered.push(node);
|
|
161
|
+
|
|
162
|
+
for (const child of node.children) {
|
|
163
|
+
if (members.has(child)) {
|
|
164
|
+
queue.push(child);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (ordered.length !== members.size) {
|
|
170
|
+
const stranded = [];
|
|
171
|
+
|
|
172
|
+
for (const node of members) {
|
|
173
|
+
if (!position.has(node)) {
|
|
174
|
+
stranded.push(node.name);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return refuse(
|
|
179
|
+
`${name}: ${stranded.length} joints are unreachable from the anchor (${stranded.join(', ')})`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const joint_count = ordered.length;
|
|
184
|
+
|
|
185
|
+
const joint = new Int32Array(joint_count);
|
|
186
|
+
const joint_parent = new Int32Array(joint_count);
|
|
187
|
+
|
|
188
|
+
const rest_position = new Float32Array(joint_count * 3);
|
|
189
|
+
const rest_rotation = new Float32Array(joint_count * 4);
|
|
190
|
+
|
|
191
|
+
const joint_name = [];
|
|
192
|
+
|
|
193
|
+
for (let i = 0; i < joint_count; i++) {
|
|
194
|
+
const node = ordered[i];
|
|
195
|
+
|
|
196
|
+
const resolved = index_of.get(node);
|
|
197
|
+
|
|
198
|
+
if (resolved === undefined) {
|
|
199
|
+
return refuse(`${name}: "${node.name}" is not a joint of this skin`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
joint[i] = resolved;
|
|
203
|
+
joint_parent[i] = members.has(node.parent) ? position.get(node.parent) : -1;
|
|
204
|
+
|
|
205
|
+
joint_name.push(node.name);
|
|
206
|
+
|
|
207
|
+
const local = node.transform_local;
|
|
208
|
+
|
|
209
|
+
rest_position[i * 3] = local[TRANSFORM64_TRANSLATION_OFFSET];
|
|
210
|
+
rest_position[i * 3 + 1] = local[TRANSFORM64_TRANSLATION_OFFSET + 1];
|
|
211
|
+
rest_position[i * 3 + 2] = local[TRANSFORM64_TRANSLATION_OFFSET + 2];
|
|
212
|
+
|
|
213
|
+
rest_rotation[i * 4] = local[TRANSFORM64_ROTATION_OFFSET];
|
|
214
|
+
rest_rotation[i * 4 + 1] = local[TRANSFORM64_ROTATION_OFFSET + 1];
|
|
215
|
+
rest_rotation[i * 4 + 2] = local[TRANSFORM64_ROTATION_OFFSET + 2];
|
|
216
|
+
rest_rotation[i * 4 + 3] = local[TRANSFORM64_ROTATION_OFFSET + 3];
|
|
217
|
+
|
|
218
|
+
// A joint at no distance from its parent is a zero-length link, which
|
|
219
|
+
// has no direction for a stretch row's gradient and no rest length for
|
|
220
|
+
// it to hold. §7 P8 rejects it at build time rather than tolerating it
|
|
221
|
+
// at runtime, which is what "build-time validation, not runtime
|
|
222
|
+
// tolerance" means. The root is included: its parent is the anchor.
|
|
223
|
+
const length = Math.hypot(
|
|
224
|
+
rest_position[i * 3], rest_position[i * 3 + 1], rest_position[i * 3 + 2]
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
if (length <= 0) {
|
|
228
|
+
return refuse(
|
|
229
|
+
`${name}: "${node.name}" sits exactly on its parent, so the link between them`
|
|
230
|
+
+ ` has no length and no direction`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
proxy: ClothProxy.from({
|
|
237
|
+
name,
|
|
238
|
+
joint,
|
|
239
|
+
joint_parent,
|
|
240
|
+
anchor,
|
|
241
|
+
rest_position,
|
|
242
|
+
rest_rotation,
|
|
243
|
+
joint_name
|
|
244
|
+
}),
|
|
245
|
+
error: ""
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @param {string} error
|
|
251
|
+
* @returns {ClothProxyBuildResult}
|
|
252
|
+
* @private
|
|
253
|
+
*/
|
|
254
|
+
function refuse(error) {
|
|
255
|
+
return { proxy: null, error };
|
|
256
|
+
}
|