@woosh/meep-engine 3.25.0 → 3.27.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.
Files changed (295) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
  3. package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
  4. package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
  5. package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
  6. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
  7. package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
  8. package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
  9. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
  10. package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
  11. package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
  12. package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
  13. package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
  14. package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
  15. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +66 -0
  16. package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
  17. package/src/core/geom/3d/shape/HeightMapShape3D.js +314 -20
  18. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  19. package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
  20. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  21. package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
  22. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  23. package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
  24. package/src/engine/physics/cloth/MEASUREMENTS.md +582 -0
  25. package/src/engine/physics/cloth/PLAN.md +330 -49
  26. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
  27. package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
  28. package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
  29. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +65 -7
  30. package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
  31. package/src/engine/physics/cloth/ecs/ClothInstance.js +72 -8
  32. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +25 -4
  33. package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
  34. package/src/engine/physics/cloth/ecs/ClothSystem.js +75 -8
  35. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +41 -4
  36. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  37. package/src/engine/physics/cloth/ecs/ClothWorld.js +207 -63
  38. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +10 -0
  39. package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
  40. package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +17 -1
  41. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +27 -3
  42. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
  43. package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +28 -3
  44. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +75 -10
  45. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
  46. package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +131 -12
  47. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
  48. package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
  49. package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
  50. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
  51. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
  52. package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
  53. package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
  54. package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
  55. package/src/engine/physics/cloth/playground/collide_main.js +1 -1
  56. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
  57. package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
  58. package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
  59. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +12 -2
  60. package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
  61. package/src/engine/physics/cloth/solver/cloth_solver_constants.js +12 -2
  62. package/src/engine/physics/cloth/solver/cloth_step_instance.js +1 -1
  63. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
  64. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
  65. package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
  66. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +23 -9
  67. package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -1
  68. package/src/engine/physics/cloth/wind/AbstractClothWind.js +23 -9
  69. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +7 -5
  70. package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -1
  71. package/src/engine/physics/cloth/wind/ClothAmbientWind.js +12 -9
  72. package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
  73. package/src/engine/physics/cloth/wind/ClothFluidWind.js +5 -2
  74. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +7 -2
  75. package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
  76. package/src/engine/physics/cloth/wind/cloth_sample_air.js +12 -5
  77. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  78. package/src/shade/playground/vgeo_runtime/README.md +167 -22
  79. package/src/shade/playground/vgeo_runtime/index.html +112 -62
  80. package/src/shade/playground/vgeo_runtime/main.js +660 -83
  81. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
  82. package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
  83. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
  84. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  85. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
  86. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
  88. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
  89. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
  90. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
  91. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
  92. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  93. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
  94. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +56 -9
  96. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  97. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
  98. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
  99. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  100. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
  101. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
  102. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  103. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
  104. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
  105. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  106. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
  107. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
  108. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  109. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
  110. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
  111. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
  112. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
  113. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
  114. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
  115. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
  116. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
  117. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
  118. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
  119. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
  120. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
  121. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
  122. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
  123. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
  124. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
  125. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
  127. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
  128. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
  129. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
  130. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
  131. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  132. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
  133. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
  134. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  135. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
  136. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
  137. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
  138. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
  139. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
  140. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
  141. package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
  142. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
  143. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
  144. package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
  145. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
  146. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
  147. package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
  148. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
  149. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
  150. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
  151. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
  152. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
  153. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
  154. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  155. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +55 -0
  156. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  157. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +202 -13
  158. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  159. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +147 -10
  160. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
  161. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
  162. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
  163. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
  164. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
  165. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  166. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
  167. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
  168. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
  169. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
  170. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
  171. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  172. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
  173. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
  174. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
  175. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
  181. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
  182. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
  183. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
  184. package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
  185. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
  186. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
  208. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
  209. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
  210. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  211. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
  212. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
  213. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
  214. package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
  215. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  216. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
  217. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  218. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
  219. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  220. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
  221. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
  222. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
  223. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
  224. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
  225. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
  226. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
  227. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
  228. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
  229. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
  230. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
  231. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
  232. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
  233. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
  234. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
  235. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
  236. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
  237. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
  238. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
  239. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
  240. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
  241. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
  242. package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
  243. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
  244. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
  245. package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
  246. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
  247. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
  248. package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
  249. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
  250. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
  251. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
  252. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
  253. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  254. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
  255. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  256. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
  257. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  258. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  259. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
  260. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  261. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
  262. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  263. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  264. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
  265. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
  266. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  267. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
  268. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  269. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
  270. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  271. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
  272. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  273. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
  274. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  275. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
  276. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  277. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
  278. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  279. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +7 -1
  280. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  281. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +7 -1
  282. package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
  283. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  284. package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
  285. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  286. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
  287. package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
  288. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  289. package/src/shade/renderer/view/GPUViewContext.js +21 -0
  290. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  291. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
  292. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
  293. package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
  294. package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
  295. package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
@@ -6,7 +6,8 @@
6
6
  * its low nibble the match length less four; either saturates at fifteen and continues in whole
7
7
  * bytes, a 255 meaning "and more". The match's distance is a 16-bit little-endian offset back from
8
8
  * the write head, and it is allowed to reach into bytes this same sequence is producing — that
9
- * overlap is how the format codes runs, so the copy has to go a byte at a time.
9
+ * overlap is how the format codes runs, so a match that reaches back less far than it is long is
10
+ * copied a byte at a time.
10
11
  *
11
12
  * Blocks here are independent: a match reaches back no further than `destination_offset`, never
12
13
  * into whatever a previous block left in the buffer. That is what `LZ4_compress_default` produces
@@ -1 +1 @@
1
- {"version":3,"file":"lz4_decompress_block.d.ts","sourceRoot":"","sources":["../../../../../src/core/binary/lz4/lz4_decompress_block.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,kDATW,UAAU,sBACV,MAAM,mBACN,MAAM,UACN,UAAU,iBACV,MAAM,cACN,MAAM,GACJ,MAAM,CA8GlB"}
1
+ {"version":3,"file":"lz4_decompress_block.d.ts","sourceRoot":"","sources":["../../../../../src/core/binary/lz4/lz4_decompress_block.js"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,kDATW,UAAU,sBACV,MAAM,mBACN,MAAM,UACN,UAAU,iBACV,MAAM,cACN,MAAM,GACJ,MAAM,CAyHlB"}
@@ -1,5 +1,18 @@
1
1
  import { assert } from "../../assert.js";
2
2
 
3
+ /**
4
+ * Runs shorter than this are cheaper to copy a byte at a time than to hand to `set` or
5
+ * `copyWithin`, whose call overhead dominates until there is a memmove's worth of work behind it.
6
+ * Both halves earn their keep, and on real geometry it is the literals that carry the win: four
7
+ * fifths of a decoded `.vgeo` page arrives as literal runs of about thirty-five bytes, while its
8
+ * matches average nine and stay in the loop whatever this is set to.
9
+ *
10
+ * Swept on 2,267 real pages at both block shapes. The top of the curve is broad — anything from
11
+ * sixteen up is most of the win — and this is where it sits, which is also where
12
+ * {@link lz4_compress_block} put its own, arrived at separately and on literals alone.
13
+ */
14
+ const BULK_COPY_LENGTH = 32;
15
+
3
16
  /**
4
17
  * Decode one LZ4 block.
5
18
  *
@@ -8,7 +21,8 @@ import { assert } from "../../assert.js";
8
21
  * its low nibble the match length less four; either saturates at fifteen and continues in whole
9
22
  * bytes, a 255 meaning "and more". The match's distance is a 16-bit little-endian offset back from
10
23
  * the write head, and it is allowed to reach into bytes this same sequence is producing — that
11
- * overlap is how the format codes runs, so the copy has to go a byte at a time.
24
+ * overlap is how the format codes runs, so a match that reaches back less far than it is long is
25
+ * copied a byte at a time.
12
26
  *
13
27
  * Blocks here are independent: a match reaches back no further than `destination_offset`, never
14
28
  * into whatever a previous block left in the buffer. That is what `LZ4_compress_default` produces
@@ -72,8 +86,12 @@ export function lz4_decompress_block(destination, destination_offset, destinatio
72
86
  );
73
87
  }
74
88
 
75
- for (let i = 0; i < literal_length; i++) {
76
- destination[d + i] = source[s + i];
89
+ if (literal_length >= BULK_COPY_LENGTH) {
90
+ destination.set(source.subarray(s, s + literal_length), d);
91
+ } else {
92
+ for (let i = 0; i < literal_length; i++) {
93
+ destination[d + i] = source[s + i];
94
+ }
77
95
  }
78
96
 
79
97
  d += literal_length;
@@ -127,9 +145,16 @@ export function lz4_decompress_block(destination, destination_offset, destinatio
127
145
  );
128
146
  }
129
147
 
130
- // a byte at a time: the match is allowed to overlap what it is writing, which is how runs are coded
131
- for (let i = 0; i < match_length; i++) {
132
- destination[d + i] = destination[match_position + i];
148
+ // A match that does not reach back as far as it is long overlaps the bytes it is writing, and
149
+ // that is how the format codes runs: `copyWithin` moves as if through a temporary, so it
150
+ // would lay down one copy of the pattern where the format means it to repeat. Only a match
151
+ // clear of its own output can take it, and the byte loop below is the run.
152
+ if (match_length >= BULK_COPY_LENGTH && match_offset >= match_length) {
153
+ destination.copyWithin(d, match_position, match_position + match_length);
154
+ } else {
155
+ for (let i = 0; i < match_length; i++) {
156
+ destination[d + i] = destination[match_position + i];
157
+ }
133
158
  }
134
159
 
135
160
  d += match_length;
@@ -158,6 +158,72 @@ export class HeightMapShape3D extends AbstractShape3D {
158
158
  * site is forced to handle heightmaps explicitly.
159
159
  */
160
160
  support(result: any, result_offset: any, direction_x: any, direction_y: any, direction_z: any): void;
161
+ /**
162
+ * Nearest ray hit against the height-field SURFACE, in the shape's body-local
163
+ * frame. Writes `[px, py, pz, nx, ny, nz]` into `hit` and returns true; a miss
164
+ * returns false and leaves `hit` untouched.
165
+ *
166
+ * ## What is hit
167
+ *
168
+ * The surface, not the solid. The class models a closed volume (floor at h=0,
169
+ * height field above), but a ray meets only the height field — there is no
170
+ * floor quad and no side skirt, so a ray that passes under the terrain or
171
+ * enters through the footprint edge below the surface reports a miss. That is
172
+ * the same body {@link heightmap_enumerate_triangles} hands the contact
173
+ * narrowphase, and the same body the terrain renderer draws; a raycast that
174
+ * answered for the skirt would disagree with both. Mirrors
175
+ * {@link MeshShape3D#raycast}, which is likewise surface-only.
176
+ *
177
+ * Precisely the same triangles, too: the traversal reads its corner heights at
178
+ * the identical `i / seg_u` / `j / seg_v` UVs through the identical Catmull-Rom
179
+ * filter, and splits each sub-cell on the same lower-left diagonal
180
+ * (`(A,D,B)`, `(D,C,B)`), so a cast and a contact resolve against a surface
181
+ * that agrees bit for bit — {@link tessellation} included.
182
+ *
183
+ * NORMAL: the triangle's geometric normal, flipped to face the incoming ray
184
+ * (the shared {@link tri3_raycast} convention). A cast from below the terrain
185
+ * therefore reports a downward normal, not the surface's true upward one.
186
+ *
187
+ * A hit landing exactly ON a seam between facets gets the normal of one of the
188
+ * facets meeting there. INSIDE a sub-cell the two paths agree — they split on
189
+ * the same D–B diagonal and break the resulting tie in favour of the same
190
+ * facet — which matters because that diagonal runs through the sub-cell's
191
+ * centre, so a cast down the middle of a cell lands on it routinely rather
192
+ * than exceptionally.
193
+ *
194
+ * BETWEEN sub-cells they can differ, and which facet each names follows from
195
+ * traversal order: this walks the grid along the ray, the narrowphase
196
+ * enumerates it row-major, so on a grid line — and especially a grid corner,
197
+ * where four facets meet — the two can name different facets. The hit POINT
198
+ * still agrees; a faceted surface simply has no single normal at a seam.
199
+ * Measure-zero, and called out because it is the only place the two answers
200
+ * part company.
201
+ *
202
+ * `size.y` does NOT bound the query. Sampler values are not clamped to it (see
203
+ * the class docstring), so clipping the ray to the height range that
204
+ * {@link compute_bounding_box} reports could reject real surface standing above
205
+ * it; only the footprint is clipped against.
206
+ *
207
+ * ## Cost
208
+ *
209
+ * A 2-D DDA over the `(W−1)·N × (H−1)·N` sub-cell grid, two triangles per cell,
210
+ * stopping at the first cell that hits — cells are visited in increasing ray
211
+ * order and a sub-cell's triangles project exactly onto its own footprint
212
+ * rectangle, so nothing behind can be nearer. O(cells the ray crosses), not
213
+ * O(cells in the ray's bounding box): a long diagonal cast costs the grid's
214
+ * diagonal rather than its area.
215
+ *
216
+ * Four Catmull-Rom evaluations per cell, uncached — deliberately unlike
217
+ * {@link heightmap_enumerate_triangles}, whose corner-row cache exists because
218
+ * the contact narrowphase re-samples the same rect every substep. A ray walks
219
+ * a diagonal, visits each cell once, and stops early; there is nothing to
220
+ * amortise against.
221
+ *
222
+ * @param {Float32Array|number[]} hit out: [px, py, pz, nx, ny, nz]
223
+ * @param {Ray3} ray body-local ray (unit direction; `ray[6]` = tMax)
224
+ * @returns {boolean} whether anything was hit
225
+ */
226
+ raycast(hit: Float32Array | number[], ray: Ray3): boolean;
161
227
  sample_random_point_in_volume(result: any, result_offset: any, random: any): void;
162
228
  /**
163
229
  * @param {HeightMapShape3D} other
@@ -1 +1 @@
1
- {"version":3,"file":"HeightMapShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/HeightMapShape3D.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH;IA4DI;;;;;;;;;;;OAWG;IACH,wCATW,MAAM,UACN,MAAM,UACN,MAAM,gBACN,OAAO,iBACP,MAAM,GAGJ,gBAAgB,CAqB5B;IA1FD;;;;;OAKG;IACH,sBAFU,OAAO,CAEkB;IAEnC;;;;;;;OAOG;IACH,eAFU,OAAO,CAEW;IAE5B;;;;;OAKG;IACH,SAFU,YAAY,IAAI,CAEX;IAEf;;;;;;;;;;;;;;;;OAgBG;IACH,cAFU,MAAM,CAEC;IAEjB;;;;;OAKG;IACH,eAA6B;IAG7B,6BAA2B;IAE3B,6BAA2B;IAC3B,6BAA2B;IAmC3B;;;;;;;;;OASG;IACH,sBA+CC;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;OAQG;IACH,8BALW,MAAM,MACN,MAAM,MACN,MAAM,GACJ,MAAM,CAelB;IAED,wCA8BC;IAED,oCA2BC;IAED;;;;;;;;OAQG;IACH,6CAmBC;IAED;;;;OAIG;IACH,4DA2BC;IAED;;;;;;;;;OASG;IACH,qGAEC;IAED,kFAiBC;IA6CD;;;OAGG;IACH,cAHW,gBAAgB,GACd,OAAO,CAUnB;IAWL;;;;;;OAMG;IACH,6BAFU,OAAO,CAE4B;CAT5C;gCAhc+B,sBAAsB;wBAD9B,kBAAkB"}
1
+ {"version":3,"file":"HeightMapShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/HeightMapShape3D.js"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH;IA4DI;;;;;;;;;;;OAWG;IACH,wCATW,MAAM,UACN,MAAM,UACN,MAAM,gBACN,OAAO,iBACP,MAAM,GAGJ,gBAAgB,CAqB5B;IA1FD;;;;;OAKG;IACH,sBAFU,OAAO,CAEkB;IAEnC;;;;;;;OAOG;IACH,eAFU,OAAO,CAEW;IAE5B;;;;;OAKG;IACH,SAFU,YAAY,IAAI,CAEX;IAEf;;;;;;;;;;;;;;;;OAgBG;IACH,cAFU,MAAM,CAEC;IAEjB;;;;;OAKG;IACH,eAA6B;IAG7B,6BAA2B;IAE3B,6BAA2B;IAC3B,6BAA2B;IAmC3B;;;;;;;;;OASG;IACH,sBA8CC;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,OACN,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;;;OAQG;IACH,8BALW,MAAM,MACN,MAAM,MACN,MAAM,GACJ,MAAM,CAelB;IAED,wCA6BC;IAED,oCA2BC;IAED;;;;;;;;OAQG;IACH,6CAmBC;IAED;;;;OAIG;IACH,4DA2BC;IAED;;;;;;;;;OASG;IACH,qGAEC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgEG;IACH,aAJW,YAAY,GAAC,MAAM,EAAE,cAEnB,OAAO,CA0NnB;IAED,kFAiBC;IA6CD;;;OAGG;IACH,cAHW,gBAAgB,GACd,OAAO,CAUnB;IAWL;;;;;;OAMG;IACH,6BAFU,OAAO,CAE4B;CAT5C;gCAluB+B,sBAAsB;wBAD9B,kBAAkB"}
@@ -2,12 +2,25 @@ import { hash_mix3 } from "../../../math/hash/hash_mix3.js";
2
2
  import { hash_mix2 } from "../../../math/hash/hash_mix2.js";
3
3
  import { assert } from "../../../assert.js";
4
4
  import { clamp } from "../../../math/clamp.js";
5
+ import { clamp_index } from "../../../math/clamp_index.js";
5
6
  import { optional_equality } from "../../../model/object/optional_equality.js";
6
7
  import { optional_hash } from "../../../model/object/optional_hash.js";
8
+ import { tri3_raycast } from "../triangle/tri3_raycast.js";
9
+ import { v3_cross } from "../../vec3/v3_cross.js";
10
+ import { v3_dot } from "../../vec3/v3_dot.js";
7
11
  import { v3_length } from "../../vec3/v3_length.js";
8
12
  import { Vector3 } from "../../Vector3.js";
9
13
  import { AbstractShape3D } from "./AbstractShape3D.js";
10
14
 
15
+ /**
16
+ * Below this, a ray's footprint-plane velocity component counts as zero in
17
+ * {@link HeightMapShape3D#raycast}'s slab clip — the reciprocal a smaller value
18
+ * would produce is not a usable slab distance. Matches the concave narrowphase's
19
+ * `refine_ray_concave`, so the two agree on rays that graze the footprint edge.
20
+ * @type {number}
21
+ */
22
+ const RAY_SLAB_EPSILON = 1e-12;
23
+
11
24
  /**
12
25
  * Heightmap shape, intended primarily for terrain.
13
26
  *
@@ -182,14 +195,13 @@ export class HeightMapShape3D extends AbstractShape3D {
182
195
  u_y *= u_inv;
183
196
  u_z *= u_inv;
184
197
 
185
- // v = u × n (for n=+Y, u=+X this gives v=+Z, the intuitive choice)
186
- const v_x = u_y * nz - u_z * ny;
187
- const v_y = u_z * nx - u_x * nz;
188
- const v_z = u_x * ny - u_y * nx;
189
-
190
198
  const b = this._basis;
199
+
191
200
  b[0] = u_x; b[1] = u_y; b[2] = u_z;
192
- b[3] = v_x; b[4] = v_y; b[5] = v_z;
201
+
202
+ // v = u × n (for n=+Y, u=+X this gives v=+Z, the intuitive choice)
203
+ v3_cross(b, 3, u_x, u_y, u_z, nx, ny, nz);
204
+
193
205
  b[6] = nx; b[7] = ny; b[8] = nz;
194
206
 
195
207
  this._basis_orientation_x = nx;
@@ -223,8 +235,8 @@ export class HeightMapShape3D extends AbstractShape3D {
223
235
  const b = this._basis;
224
236
 
225
237
  // project onto basis u and basis v
226
- const u_coord = b[0] * px + b[1] * py + b[2] * pz;
227
- const v_coord = b[3] * px + b[4] * py + b[5] * pz;
238
+ const u_coord = v3_dot(b[0], b[1], b[2], px, py, pz);
239
+ const v_coord = v3_dot(b[3], b[4], b[5], px, py, pz);
228
240
 
229
241
  const u01 = u_coord / this.size[0] + 0.5;
230
242
  const v01 = v_coord / this.size[2] + 0.5;
@@ -256,11 +268,10 @@ export class HeightMapShape3D extends AbstractShape3D {
256
268
 
257
269
  const uv_extent = Math.abs(cu) * half_u + Math.abs(cv) * half_v;
258
270
 
259
- const h_lo = ch < 0 ? ch * sy : 0;
260
- const h_hi = ch > 0 ? ch * sy : 0;
271
+ const h_extent = ch * sy;
261
272
 
262
- result[k] = -uv_extent + h_lo;
263
- result[k + 3] = uv_extent + h_hi;
273
+ result[k] = -uv_extent + Math.min(h_extent, 0);
274
+ result[k + 3] = uv_extent + Math.max(h_extent, 0);
264
275
  }
265
276
  }
266
277
 
@@ -274,9 +285,9 @@ export class HeightMapShape3D extends AbstractShape3D {
274
285
  const b = this._basis;
275
286
 
276
287
  // project into heightmap-local frame (u, v, h)
277
- const u_coord = b[0] * px + b[1] * py + b[2] * pz;
278
- const v_coord = b[3] * px + b[4] * py + b[5] * pz;
279
- const h_coord = b[6] * px + b[7] * py + b[8] * pz;
288
+ const u_coord = v3_dot(b[0], b[1], b[2], px, py, pz);
289
+ const v_coord = v3_dot(b[3], b[4], b[5], px, py, pz);
290
+ const h_coord = v3_dot(b[6], b[7], b[8], px, py, pz);
280
291
 
281
292
  const half_u = this.size[0] * 0.5;
282
293
  const half_v = this.size[2] * 0.5;
@@ -311,9 +322,9 @@ export class HeightMapShape3D extends AbstractShape3D {
311
322
 
312
323
  const b = this._basis;
313
324
 
314
- const u_coord = b[0] * px + b[1] * py + b[2] * pz;
315
- const v_coord = b[3] * px + b[4] * py + b[5] * pz;
316
- const h_coord = b[6] * px + b[7] * py + b[8] * pz;
325
+ const u_coord = v3_dot(b[0], b[1], b[2], px, py, pz);
326
+ const v_coord = v3_dot(b[3], b[4], b[5], px, py, pz);
327
+ const h_coord = v3_dot(b[6], b[7], b[8], px, py, pz);
317
328
 
318
329
  const u01 = u_coord / this.size[0] + 0.5;
319
330
  const v01 = v_coord / this.size[2] + 0.5;
@@ -337,8 +348,8 @@ export class HeightMapShape3D extends AbstractShape3D {
337
348
 
338
349
  const b = this._basis;
339
350
 
340
- const u_coord = b[0] * rx + b[1] * ry + b[2] * rz;
341
- const v_coord = b[3] * rx + b[4] * ry + b[5] * rz;
351
+ const u_coord = v3_dot(b[0], b[1], b[2], rx, ry, rz);
352
+ const v_coord = v3_dot(b[3], b[4], b[5], rx, ry, rz);
342
353
 
343
354
  const half_u = this.size[0] * 0.5;
344
355
  const half_v = this.size[2] * 0.5;
@@ -371,6 +382,289 @@ export class HeightMapShape3D extends AbstractShape3D {
371
382
  throw new Error("HeightMapShape3D.support: heightmaps are non-convex; the narrowphase must dispatch grid-traversal instead.");
372
383
  }
373
384
 
385
+ /**
386
+ * Nearest ray hit against the height-field SURFACE, in the shape's body-local
387
+ * frame. Writes `[px, py, pz, nx, ny, nz]` into `hit` and returns true; a miss
388
+ * returns false and leaves `hit` untouched.
389
+ *
390
+ * ## What is hit
391
+ *
392
+ * The surface, not the solid. The class models a closed volume (floor at h=0,
393
+ * height field above), but a ray meets only the height field — there is no
394
+ * floor quad and no side skirt, so a ray that passes under the terrain or
395
+ * enters through the footprint edge below the surface reports a miss. That is
396
+ * the same body {@link heightmap_enumerate_triangles} hands the contact
397
+ * narrowphase, and the same body the terrain renderer draws; a raycast that
398
+ * answered for the skirt would disagree with both. Mirrors
399
+ * {@link MeshShape3D#raycast}, which is likewise surface-only.
400
+ *
401
+ * Precisely the same triangles, too: the traversal reads its corner heights at
402
+ * the identical `i / seg_u` / `j / seg_v` UVs through the identical Catmull-Rom
403
+ * filter, and splits each sub-cell on the same lower-left diagonal
404
+ * (`(A,D,B)`, `(D,C,B)`), so a cast and a contact resolve against a surface
405
+ * that agrees bit for bit — {@link tessellation} included.
406
+ *
407
+ * NORMAL: the triangle's geometric normal, flipped to face the incoming ray
408
+ * (the shared {@link tri3_raycast} convention). A cast from below the terrain
409
+ * therefore reports a downward normal, not the surface's true upward one.
410
+ *
411
+ * A hit landing exactly ON a seam between facets gets the normal of one of the
412
+ * facets meeting there. INSIDE a sub-cell the two paths agree — they split on
413
+ * the same D–B diagonal and break the resulting tie in favour of the same
414
+ * facet — which matters because that diagonal runs through the sub-cell's
415
+ * centre, so a cast down the middle of a cell lands on it routinely rather
416
+ * than exceptionally.
417
+ *
418
+ * BETWEEN sub-cells they can differ, and which facet each names follows from
419
+ * traversal order: this walks the grid along the ray, the narrowphase
420
+ * enumerates it row-major, so on a grid line — and especially a grid corner,
421
+ * where four facets meet — the two can name different facets. The hit POINT
422
+ * still agrees; a faceted surface simply has no single normal at a seam.
423
+ * Measure-zero, and called out because it is the only place the two answers
424
+ * part company.
425
+ *
426
+ * `size.y` does NOT bound the query. Sampler values are not clamped to it (see
427
+ * the class docstring), so clipping the ray to the height range that
428
+ * {@link compute_bounding_box} reports could reject real surface standing above
429
+ * it; only the footprint is clipped against.
430
+ *
431
+ * ## Cost
432
+ *
433
+ * A 2-D DDA over the `(W−1)·N × (H−1)·N` sub-cell grid, two triangles per cell,
434
+ * stopping at the first cell that hits — cells are visited in increasing ray
435
+ * order and a sub-cell's triangles project exactly onto its own footprint
436
+ * rectangle, so nothing behind can be nearer. O(cells the ray crosses), not
437
+ * O(cells in the ray's bounding box): a long diagonal cast costs the grid's
438
+ * diagonal rather than its area.
439
+ *
440
+ * Four Catmull-Rom evaluations per cell, uncached — deliberately unlike
441
+ * {@link heightmap_enumerate_triangles}, whose corner-row cache exists because
442
+ * the contact narrowphase re-samples the same rect every substep. A ray walks
443
+ * a diagonal, visits each cell once, and stops early; there is nothing to
444
+ * amortise against.
445
+ *
446
+ * @param {Float32Array|number[]} hit out: [px, py, pz, nx, ny, nz]
447
+ * @param {Ray3} ray body-local ray (unit direction; `ray[6]` = tMax)
448
+ * @returns {boolean} whether anything was hit
449
+ */
450
+ raycast(hit, ray) {
451
+ const sampler = this.sampler;
452
+
453
+ if (sampler === null) {
454
+ return false;
455
+ }
456
+
457
+ const size_x = this.size[0];
458
+ const size_z = this.size[2];
459
+
460
+ if (size_x <= 0 || size_z <= 0) {
461
+ return false;
462
+ }
463
+
464
+ // The collision grid heightmap_enumerate_triangles builds. A sampler too
465
+ // thin to hold one cell on an axis (width or height < 2), or tessellation
466
+ // 0, collapses it — no triangles exist, so nothing can be hit.
467
+ const seg_u = (sampler.width - 1) * this.tessellation;
468
+ const seg_v = (sampler.height - 1) * this.tessellation;
469
+
470
+ if (seg_u < 1 || seg_v < 1) {
471
+ return false;
472
+ }
473
+
474
+ this._ensure_basis();
475
+
476
+ const b = this._basis;
477
+
478
+ const o_x = ray[0], o_y = ray[1], o_z = ray[2];
479
+ const d_x = ray[3], d_y = ray[4], d_z = ray[5];
480
+
481
+ // Body → heightmap-local footprint coordinates. The basis is orthonormal,
482
+ // so the direction stays unit and `t` is the same distance in both frames;
483
+ // the height component is never needed, the triangles carry it.
484
+ const o_u = v3_dot(b[0], b[1], b[2], o_x, o_y, o_z);
485
+ const o_v = v3_dot(b[3], b[4], b[5], o_x, o_y, o_z);
486
+ const d_u = v3_dot(b[0], b[1], b[2], d_x, d_y, d_z);
487
+ const d_v = v3_dot(b[3], b[4], b[5], d_x, d_y, d_z);
488
+
489
+ const half_u = size_x * 0.5;
490
+ const half_v = size_z * 0.5;
491
+
492
+ const t_max = ray[6];
493
+
494
+ // ── Clip to the footprint slabs → the segment the DDA walks ──────────
495
+ let t_enter = 0;
496
+ let t_exit = t_max;
497
+
498
+ if (d_u > RAY_SLAB_EPSILON || d_u < -RAY_SLAB_EPSILON) {
499
+ const inv = 1 / d_u;
500
+ const t0 = (-half_u - o_u) * inv;
501
+ const t1 = (half_u - o_u) * inv;
502
+
503
+ t_enter = Math.max(t_enter, Math.min(t0, t1));
504
+ t_exit = Math.min(t_exit, Math.max(t0, t1));
505
+ } else if (o_u < -half_u || o_u > half_u) {
506
+ return false;
507
+ }
508
+
509
+ if (d_v > RAY_SLAB_EPSILON || d_v < -RAY_SLAB_EPSILON) {
510
+ const inv = 1 / d_v;
511
+ const t0 = (-half_v - o_v) * inv;
512
+ const t1 = (half_v - o_v) * inv;
513
+
514
+ t_enter = Math.max(t_enter, Math.min(t0, t1));
515
+ t_exit = Math.min(t_exit, Math.max(t0, t1));
516
+ } else if (o_v < -half_v || o_v > half_v) {
517
+ return false;
518
+ }
519
+
520
+ if (t_exit < t_enter) {
521
+ return false;
522
+ }
523
+
524
+ // ── Amanatides–Woo setup on the sub-cell grid ────────────────────────
525
+ //
526
+ // Grid coordinates run [0, seg_u] × [0, seg_v] across the footprint. A
527
+ // ray with no footprint-plane velocity (cast straight down the
528
+ // orientation axis) keeps both rates at 0, both t_next at Infinity, and
529
+ // the loop tests its single cell and stops.
530
+ const per_cell_u = seg_u / size_x;
531
+ const per_cell_v = seg_v / size_z;
532
+
533
+ const rate_u = d_u * per_cell_u;
534
+ const rate_v = d_v * per_cell_v;
535
+
536
+ const g_u = (o_u + d_u * t_enter + half_u) * per_cell_u;
537
+ const g_v = (o_v + d_v * t_enter + half_v) * per_cell_v;
538
+
539
+ // Clamped to the grid because the slab clip lands the entry point ON the
540
+ // boundary, where rounding can put it a ULP outside.
541
+ let i = clamp_index(Math.floor(g_u), seg_u);
542
+ let j = clamp_index(Math.floor(g_v), seg_v);
543
+
544
+ // `t_next` is the distance at which the ray leaves the starting cell
545
+ // through that axis' far grid line, `t_delta` the distance a whole cell
546
+ // costs thereafter. A zero rate leaves both at Infinity: that axis is
547
+ // never the one the walk steps along.
548
+ let step_i = 0, t_delta_u = Infinity, t_next_u = Infinity;
549
+ if (rate_u !== 0) {
550
+ // the grid line the starting cell is left through: its far side
551
+ // in the direction of travel
552
+ const exit_line = rate_u > 0 ? i + 1 : i;
553
+
554
+ step_i = rate_u > 0 ? 1 : -1;
555
+ t_delta_u = Math.abs(1 / rate_u);
556
+ t_next_u = t_enter + (exit_line - g_u) / rate_u;
557
+ }
558
+
559
+ let step_j = 0, t_delta_v = Infinity, t_next_v = Infinity;
560
+ if (rate_v !== 0) {
561
+ const exit_line = rate_v > 0 ? j + 1 : j;
562
+
563
+ step_j = rate_v > 0 ? 1 : -1;
564
+ t_delta_v = Math.abs(1 / rate_v);
565
+ t_next_v = t_enter + (exit_line - g_v) / rate_v;
566
+ }
567
+
568
+ const inv_seg_u = 1 / seg_u;
569
+ const inv_seg_v = 1 / seg_v;
570
+
571
+ const ux = b[0], uy = b[1], uz = b[2];
572
+ const vx = b[3], vy = b[4], vz = b[5];
573
+ const nx = b[6], ny = b[7], nz = b[8];
574
+
575
+ // Every iteration but the last ends by crossing one grid line, and a
576
+ // straight line crosses fewer than seg_u + seg_v of them (a corner costs
577
+ // two iterations to move diagonally — one per axis — but no extra lines).
578
+ // The walk normally ends on t_exit; this is the bound that holds when a
579
+ // near-denormal rate makes t_exit unreachable.
580
+ const max_steps = seg_u + seg_v + 2;
581
+
582
+ for (let step = 0; step < max_steps; step++) {
583
+ // ── The sub-cell's two triangles, built exactly as the enumerator
584
+ // builds them: corners (A,B,C,D) = (i,j), (i+1,j), (i+1,j+1),
585
+ // (i,j+1), split (A,D,B) and (D,C,B).
586
+ const u01_lo = i * inv_seg_u;
587
+ const u01_hi = (i + 1) * inv_seg_u;
588
+ const v01_lo = j * inv_seg_v;
589
+ const v01_hi = (j + 1) * inv_seg_v;
590
+
591
+ const u_lo = -half_u + size_x * u01_lo;
592
+ const u_hi = -half_u + size_x * u01_hi;
593
+ const v_lo = -half_v + size_z * v01_lo;
594
+ const v_hi = -half_v + size_z * v01_hi;
595
+
596
+ const hA = sampler.sampleChannelCatmullRomUV(u01_lo, v01_lo, 0);
597
+ const hB = sampler.sampleChannelCatmullRomUV(u01_hi, v01_lo, 0);
598
+ const hC = sampler.sampleChannelCatmullRomUV(u01_hi, v01_hi, 0);
599
+ const hD = sampler.sampleChannelCatmullRomUV(u01_lo, v01_hi, 0);
600
+
601
+ const Ax = ux * u_lo + vx * v_lo + nx * hA;
602
+ const Ay = uy * u_lo + vy * v_lo + ny * hA;
603
+ const Az = uz * u_lo + vz * v_lo + nz * hA;
604
+
605
+ const Bx = ux * u_hi + vx * v_lo + nx * hB;
606
+ const By = uy * u_hi + vy * v_lo + ny * hB;
607
+ const Bz = uz * u_hi + vz * v_lo + nz * hB;
608
+
609
+ const Cx = ux * u_hi + vx * v_hi + nx * hC;
610
+ const Cy = uy * u_hi + vy * v_hi + ny * hC;
611
+ const Cz = uz * u_hi + vz * v_hi + nz * hC;
612
+
613
+ const Dx = ux * u_lo + vx * v_hi + nx * hD;
614
+ const Dy = uy * u_lo + vy * v_hi + ny * hD;
615
+ const Dz = uz * u_lo + vz * v_hi + nz * hD;
616
+
617
+ // Tested in reverse enumeration order, and that is what decides the
618
+ // tie. The two facets share the D–B diagonal — which runs through the
619
+ // sub-cell's centre, so a ray landing on it is the ordinary case, not a
620
+ // corner one — and a ray that lands on it hits both at one distance.
621
+ // `refine_ray_concave` enumerates (A,D,B) first and lets a later
622
+ // triangle win only by a strictly smaller distance, so the facet it
623
+ // names is (A,D,B). tri3_raycast admits `t <= tMax` and writes hit[3..5]
624
+ // only on a hit, so testing (D,C,B) first and handing (A,D,B) its
625
+ // distance as the budget lets the equal hit overwrite the normal — and
626
+ // the two paths name the same facet.
627
+ const t_dcb = tri3_raycast(
628
+ hit, 3, o_x, o_y, o_z, d_x, d_y, d_z, t_max,
629
+ Dx, Dy, Dz, Cx, Cy, Cz, Bx, By, Bz
630
+ );
631
+
632
+ const t_adb = tri3_raycast(
633
+ hit, 3, o_x, o_y, o_z, d_x, d_y, d_z, Math.min(t_dcb, t_max),
634
+ Ax, Ay, Az, Dx, Dy, Dz, Bx, By, Bz
635
+ );
636
+
637
+ const best = Math.min(t_adb, t_dcb);
638
+
639
+ if (best !== Infinity) {
640
+ hit[0] = o_x + d_x * best;
641
+ hit[1] = o_y + d_y * best;
642
+ hit[2] = o_z + d_z * best;
643
+
644
+ return true;
645
+ }
646
+
647
+ // ── Advance to the next cell along the ray ───────────────────────
648
+ if (t_next_u < t_next_v) {
649
+ if (t_next_u > t_exit) break;
650
+ i += step_i;
651
+ if (i < 0 || i >= seg_u) break;
652
+ t_next_u += t_delta_u;
653
+ } else if (t_next_v !== Infinity) {
654
+ if (t_next_v > t_exit) break;
655
+ j += step_j;
656
+ if (j < 0 || j >= seg_v) break;
657
+ t_next_v += t_delta_v;
658
+ } else {
659
+ // Both rates are zero: the ray runs along the orientation axis and
660
+ // never leaves the cell it started in.
661
+ break;
662
+ }
663
+ }
664
+
665
+ return false;
666
+ }
667
+
374
668
  sample_random_point_in_volume(result, result_offset, random) {
375
669
  const u01 = random();
376
670
  const v01 = random();
@@ -1 +1 @@
1
- {"version":3,"file":"PosedShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/PosedShape3D.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAEI,mCAAmC;IACnC,OADW,eAAe,GAAC,IAAI,CAClB;IAEb,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IAEP;;;;;;;OAOG;IACH,aAJW,eAAe,YACf,UAAQ;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,YACpC,aAAW;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,QAe1D;IAED;;;;;;;;;;;;;;;OAeG;IACH,wBATW,eAAe,MACf,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QAMhB;IAyED,wCASC;IA4BD;;;;;;;OAOG;IACH,gCAHW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,GAChC,MAAM,CAKlB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,GAChC,OAAO,CAKnB;IAGL;;;;OAIG;IACH,yBAFU,OAAO,CAEoB;;CAPpC;gCAtN+B,sBAAsB"}
1
+ {"version":3,"file":"PosedShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/PosedShape3D.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAEI,mCAAmC;IACnC,OADW,eAAe,GAAC,IAAI,CAClB;IAEb,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IAEP;;;;;;;OAOG;IACH,aAJW,eAAe,YACf,UAAQ;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,YACpC,aAAW;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,QAe1D;IAED;;;;;;;;;;;;;;;OAeG;IACH,wBATW,eAAe,MACf,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,MACN,MAAM,QAMhB;IA+HD,wCASC;IA4BD;;;;;;;OAOG;IACH,gCAHW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,GAChC,MAAM,CAKlB;IAED;;;;;OAKG;IACH,sBAHW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,GAChC,OAAO,CAKnB;IAGL;;;;OAIG;IACH,yBAFU,OAAO,CAEoB;;CAPpC;gCA5Q+B,sBAAsB"}
@@ -1,5 +1,8 @@
1
1
  import { assert } from "../../../assert.js";
2
+ import { v3_quaternion_apply } from "../../vec3/v3_quaternion_apply.js";
3
+ import { v3_quaternion_apply_inverse } from "../../vec3/v3_quaternion_apply_inverse.js";
2
4
  import { aabb3_transform_oriented } from "../aabb/aabb3_transform_oriented.js";
5
+ import { Ray3 } from "../ray/Ray3.js";
3
6
  import { AbstractShape3D } from "./AbstractShape3D.js";
4
7
 
5
8
  const scratch_local = new Float64Array(3);
@@ -154,6 +157,60 @@ export class PosedShape3D extends AbstractShape3D {
154
157
  result[result_offset + 2] = tsz * qw - tsw * qz - tsx * qy + tsy * qx + this.pz;
155
158
  }
156
159
 
160
+ /**
161
+ * Ray ↔ posed shape, with the ray given in the WRAPPER's frame. The inverse pose carries it into
162
+ * the subject's frame (translate by −position, rotate by the conjugate quaternion), the subject
163
+ * answers there, and the answer is rotated back — the point re-translated, the normal not.
164
+ *
165
+ * A rigid pose is an isometry, so the crossing changes nothing about the ray's parametrisation:
166
+ * the rotated direction is still unit, `tMax` goes through untouched, and the distance the subject
167
+ * measures IS the distance here. The normal's ORIENTATION survives for the same reason — a rotation
168
+ * preserves the angle between normal and direction, so a subject that turned its normal to meet the
169
+ * ray has turned this one to meet it too, and there is nothing to re-check.
170
+ *
171
+ * `hit` is handed straight to the subject rather than buffered and copied back: on a hit its
172
+ * contents are mapped in place, and on a miss the subject leaves it untouched — which is the
173
+ * convention this class owes its own caller, so it is passed on intact.
174
+ *
175
+ * The physics ray query does not come through here; it uses `refine_ray_posed`, which performs the
176
+ * same mapping on loose scalars. That path reports a distance rather than a point, so it never
177
+ * rotates anything but the normal.
178
+ *
179
+ * @param {Float32Array|number[]} hit out: [px, py, pz, nx, ny, nz]
180
+ * @param {Ray3} ray wrapper-frame ray (origin in [0..2], unit direction in [3..5], tMax in [6])
181
+ * @returns {boolean} whether anything was hit
182
+ */
183
+ raycast(hit, ray) {
184
+ const shape = this.shape;
185
+
186
+ if (shape === null) {
187
+ return false;
188
+ }
189
+
190
+ const qx = this.qx, qy = this.qy, qz = this.qz, qw = this.qw;
191
+
192
+ // Allocated per call rather than kept as a module scratch: a posed shape may wrap another
193
+ // wrapper, and every level of that recursion needs its own sub-ray alive across the call below.
194
+ const local_ray = new Ray3();
195
+
196
+ v3_quaternion_apply_inverse(local_ray, 0, ray[0] - this.px, ray[1] - this.py, ray[2] - this.pz, qx, qy, qz, qw);
197
+ v3_quaternion_apply_inverse(local_ray, 3, ray[3], ray[4], ray[5], qx, qy, qz, qw);
198
+ local_ray[6] = ray[6];
199
+
200
+ if (!shape.raycast(hit, local_ray)) {
201
+ return false;
202
+ }
203
+
204
+ v3_quaternion_apply(hit, 0, hit[0], hit[1], hit[2], qx, qy, qz, qw);
205
+ v3_quaternion_apply(hit, 3, hit[3], hit[4], hit[5], qx, qy, qz, qw);
206
+
207
+ hit[0] += this.px;
208
+ hit[1] += this.py;
209
+ hit[2] += this.pz;
210
+
211
+ return true;
212
+ }
213
+
157
214
  compute_bounding_box(result) {
158
215
  this.shape.compute_bounding_box(scratch_local_aabb);
159
216
  aabb3_transform_oriented(
@@ -1 +1 @@
1
- {"version":3,"file":"TransformedShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/TransformedShape3D.js"],"names":[],"mappings":"AAwBA;IAwCI;;;;;OAKG;IACH,wBAHW,eAAe,MADf,MAAM,EAAE,GAAC,YAAY,OAAK,GAExB,kBAAkB,CAS9B;IAED;;;;;OAKG;IACH,uCAJW,eAAe,eACf,MAAM,EAAE,SACR,MAAM,EAAE,sBAiBlB;IAED;;;;OAIG;IACH,iCAHW,eAAe,eACf,MAAM,EAAE,sBAIlB;IAED;;;;;OAKG;IACH,2BAHW,eAAe,SACf,MAAM,EAAE,GAAC,YAAY,OAAK,GAFxB,kBAAkB,CAM9B;IA9FD;;;;OAIG;IACH,iBAAgC;IAEhC;;;;OAIG;IACH,yBAAwC;IAExC;;;;OAIG;IACH,kBAAiB;IAEjB;;;OAGG;IACH,+BAEC;IAqED;;;OAGG;IACH,0CAIC;IAED,yCAEC;IAED;;;;;;;OAOG;IACH,6BAEC;IAUD,wCAKC;IAED,mEAyDC;IAED,6CAEC;IAED,oCAKC;IAED,kFAIC;IAED,qGAwCC;IAED;;;;OAIG;IACH,cAHW,kBAAkB,GAChB,OAAO,CAOnB;IAQL;;;;;OAKG;IACH,+BAFU,OAAO,CAEgC;CARhD;gCA9R+B,sBAAsB"}
1
+ {"version":3,"file":"TransformedShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/TransformedShape3D.js"],"names":[],"mappings":"AAyBA;IAwCI;;;;;OAKG;IACH,wBAHW,eAAe,MADf,MAAM,EAAE,GAAC,YAAY,OAAK,GAExB,kBAAkB,CAS9B;IAED;;;;;OAKG;IACH,uCAJW,eAAe,eACf,MAAM,EAAE,SACR,MAAM,EAAE,sBAiBlB;IAED;;;;OAIG;IACH,iCAHW,eAAe,eACf,MAAM,EAAE,sBAIlB;IAED;;;;;OAKG;IACH,2BAHW,eAAe,SACf,MAAM,EAAE,GAAC,YAAY,OAAK,GAFxB,kBAAkB,CAM9B;IA9FD;;;;OAIG;IACH,iBAAgC;IAEhC;;;;OAIG;IACH,yBAAwC;IAExC;;;;OAIG;IACH,kBAAiB;IAEjB;;;OAGG;IACH,+BAEC;IAqED;;;OAGG;IACH,0CAIC;IAED,yCAEC;IAED;;;;;;;OAOG;IACH,6BAEC;IAUD,wCAKC;IAED,mEAyDC;IAED,6CAEC;IAED,oCAKC;IAED,kFAIC;IAED,qGAwCC;IAuGD;;;;OAIG;IACH,cAHW,kBAAkB,GAChB,OAAO,CAOnB;IAQL;;;;;OAKG;IACH,+BAFU,OAAO,CAEgC;CARhD;gCAnY+B,sBAAsB"}