@woosh/meep-engine 3.28.0 → 3.29.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 (482) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/BitSet.d.ts +16 -0
  4. package/src/core/binary/BitSet.d.ts.map +1 -1
  5. package/src/core/binary/BitSet.js +159 -49
  6. package/src/core/binary/allocator/OffsetAllocator.d.ts +48 -0
  7. package/src/core/binary/allocator/OffsetAllocator.d.ts.map +1 -1
  8. package/src/core/binary/allocator/OffsetAllocator.js +208 -9
  9. package/src/core/binary/compression/compress_bytes.d.ts +20 -0
  10. package/src/core/binary/compression/compress_bytes.d.ts.map +1 -0
  11. package/src/core/binary/compression/compress_bytes.js +35 -0
  12. package/src/core/binary/compression/decompress_bytes_into.d.ts +30 -0
  13. package/src/core/binary/compression/decompress_bytes_into.d.ts.map +1 -0
  14. package/src/core/binary/compression/decompress_bytes_into.js +87 -0
  15. package/src/core/binary/compression/deflate_decompress_bound.d.ts +27 -0
  16. package/src/core/binary/compression/deflate_decompress_bound.d.ts.map +1 -0
  17. package/src/core/binary/compression/deflate_decompress_bound.js +32 -0
  18. package/src/core/geom/3d/quadric/quadric_attribute_add.d.ts +24 -0
  19. package/src/core/geom/3d/quadric/quadric_attribute_add.d.ts.map +1 -0
  20. package/src/core/geom/3d/quadric/quadric_attribute_add.js +31 -0
  21. package/src/core/geom/3d/quadric/quadric_attribute_reduce.d.ts +46 -0
  22. package/src/core/geom/3d/quadric/quadric_attribute_reduce.d.ts.map +1 -0
  23. package/src/core/geom/3d/quadric/quadric_attribute_reduce.js +104 -0
  24. package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.d.ts +62 -0
  25. package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.d.ts.map +1 -0
  26. package/src/core/geom/3d/quadric/quadric_attribute_set_from_triangle.js +158 -0
  27. package/src/core/geom/3d/quadric/quadric_attribute_size.d.ts +21 -0
  28. package/src/core/geom/3d/quadric/quadric_attribute_size.d.ts.map +1 -0
  29. package/src/core/geom/3d/quadric/quadric_attribute_size.js +24 -0
  30. package/src/core/geom/3d/quadric/quadric_attribute_solve.d.ts +34 -0
  31. package/src/core/geom/3d/quadric/quadric_attribute_solve.d.ts.map +1 -0
  32. package/src/core/geom/3d/quadric/quadric_attribute_solve.js +55 -0
  33. package/src/core/geom/3d/quadric/quadric_attribute_sub.d.ts +28 -0
  34. package/src/core/geom/3d/quadric/quadric_attribute_sub.d.ts.map +1 -0
  35. package/src/core/geom/3d/quadric/quadric_attribute_sub.js +35 -0
  36. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.d.ts +15 -0
  37. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.d.ts.map +1 -1
  38. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.js +35 -0
  39. package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.d.ts +93 -0
  40. package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.d.ts.map +1 -0
  41. package/src/core/geom/3d/topology/struct/binary/BtWedgeSet.js +128 -0
  42. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts +38 -0
  43. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -0
  44. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +113 -0
  45. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +47 -1
  46. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  47. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +677 -8
  48. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.d.ts +22 -0
  49. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.d.ts.map +1 -0
  50. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_live_count.js +46 -0
  51. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.d.ts +19 -0
  52. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.d.ts.map +1 -0
  53. package/src/core/geom/3d/topology/struct/binary/io/bt_wedges_per_vertex.js +49 -0
  54. package/src/core/graph/layout/layered/BoxLayoutOptions.d.ts +63 -0
  55. package/src/core/graph/layout/layered/BoxLayoutOptions.d.ts.map +1 -0
  56. package/src/core/graph/layout/layered/BoxLayoutOptions.js +80 -0
  57. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/LayoutBoxGraph.d.ts +35 -0
  58. package/src/core/graph/layout/layered/LayoutBoxGraph.d.ts.map +1 -0
  59. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/LayoutBoxGraph.js +53 -1
  60. package/src/core/graph/layout/layered/layout_assign_coordinates.d.ts.map +1 -0
  61. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_coordinates.js +72 -68
  62. package/src/core/graph/layout/layered/layout_assign_layers.d.ts.map +1 -0
  63. package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_layers.js +4 -2
  64. package/src/core/graph/layout/layered/layout_break_cycles.d.ts.map +1 -0
  65. package/src/core/graph/layout/layered/layout_insert_lanes.d.ts.map +1 -0
  66. package/src/core/graph/layout/layered/layout_order_layers.d.ts.map +1 -0
  67. package/src/core/graph/layout/layered/layout_orient_links.d.ts.map +1 -0
  68. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts +7 -51
  69. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.d.ts.map +1 -1
  70. package/src/core/model/node-graph/visual/layout/NodeGraphLayoutOptions.js +8 -69
  71. package/src/core/model/node-graph/visual/layout/layout_build_problem.js +1 -1
  72. package/src/core/model/node-graph/visual/layout/layout_node_graph.js +6 -6
  73. package/src/core/model/node-graph/visual/layout/route_grid_build.js +1 -1
  74. package/src/engine/graphics3/DebugDrawSystem.d.ts +7 -5
  75. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  76. package/src/engine/graphics3/DebugDrawSystem.js +206 -203
  77. package/src/engine/graphics3/DecalSystem.d.ts +4 -5
  78. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  79. package/src/engine/graphics3/DecalSystem.js +5 -5
  80. package/src/engine/graphics3/FogOfWarSystem.d.ts +7 -12
  81. package/src/engine/graphics3/FogOfWarSystem.d.ts.map +1 -1
  82. package/src/engine/graphics3/FogOfWarSystem.js +8 -12
  83. package/src/engine/graphics3/prefab/prefab_instantiate.js +230 -230
  84. package/src/shade/RENDERER_CONTRACT.md +12 -7
  85. package/src/shade/playground/caldera/README.md +529 -0
  86. package/src/shade/playground/caldera/caldera_format.d.ts +151 -0
  87. package/src/shade/playground/caldera/caldera_format.d.ts.map +1 -0
  88. package/src/shade/playground/caldera/caldera_format.js +241 -0
  89. package/src/shade/playground/caldera/index.html +126 -0
  90. package/src/shade/playground/caldera/main.d.ts.map +1 -0
  91. package/src/shade/playground/caldera/main.js +1565 -0
  92. package/src/shade/playground/mesh_row_ceiling/README.md +85 -0
  93. package/src/shade/playground/mesh_row_ceiling/index.html +31 -0
  94. package/src/shade/playground/mesh_row_ceiling/main.d.ts +2 -0
  95. package/src/shade/playground/mesh_row_ceiling/main.d.ts.map +1 -0
  96. package/src/shade/playground/mesh_row_ceiling/main.js +389 -0
  97. package/src/shade/playground/vgeo_runtime/README.md +5 -3
  98. package/src/shade/playground/vgeo_runtime/main.js +3 -2
  99. package/src/shade/playground/vgeo_runtime/sample_asset.d.ts +3 -3
  100. package/src/shade/playground/vgeo_runtime/sample_asset.d.ts.map +1 -1
  101. package/src/shade/playground/vgeo_runtime/sample_asset.js +3 -3
  102. package/src/shade/playground/vgeo_scene/README.md +103 -24
  103. package/src/shade/playground/vgeo_scene/main.js +525 -24
  104. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  105. package/src/shade/renderer/GraphicsContext.js +6 -0
  106. package/src/shade/renderer/Renderer.d.ts +2 -0
  107. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  108. package/src/shade/renderer/Renderer.js +23 -0
  109. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
  110. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +100 -8
  111. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +69 -33
  112. package/src/shade/renderer/extension/RenderExtension.d.ts +15 -18
  113. package/src/shade/renderer/extension/RenderExtension.d.ts.map +1 -1
  114. package/src/shade/renderer/extension/RenderExtension.js +15 -19
  115. package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts +5 -5
  116. package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts.map +1 -1
  117. package/src/shade/renderer/extension/RenderExtensionRegistry.js +29 -166
  118. package/src/shade/renderer/geometry/GPUGeometryManager.d.ts.map +1 -1
  119. package/src/shade/renderer/geometry/GPUGeometryManager.js +73 -16
  120. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  121. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +18 -3
  122. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +663 -0
  123. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +100 -5
  124. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  125. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +688 -81
  126. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +540 -0
  127. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +155 -64
  128. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +30 -13
  129. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +3 -3
  130. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +358 -0
  131. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +57 -7
  132. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  133. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +63 -9
  134. package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.d.ts +40 -0
  135. package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.d.ts.map +1 -0
  136. package/src/shade/renderer/geometry/virtual/build/level/VGeoContribution.js +24 -0
  137. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts +91 -0
  138. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts.map +1 -0
  139. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.js +91 -0
  140. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.d.ts +24 -0
  141. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.d.ts.map +1 -0
  142. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupRepack.js +25 -0
  143. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts +77 -0
  144. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts.map +1 -0
  145. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.js +84 -0
  146. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts +19 -6
  147. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.d.ts.map +1 -1
  148. package/src/shade/renderer/geometry/virtual/build/level/VGeoLevelOptions.js +20 -7
  149. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.d.ts +19 -0
  150. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.d.ts.map +1 -0
  151. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster.js +58 -0
  152. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.d.ts +18 -0
  153. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.d.ts.map +1 -0
  154. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_cluster_graph.js +116 -0
  155. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts +18 -0
  156. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -0
  157. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +545 -0
  158. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts +16 -0
  159. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -0
  160. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +110 -0
  161. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts +2 -27
  162. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -1
  163. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.js +120 -1564
  164. package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.d.ts +26 -0
  165. package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.d.ts.map +1 -0
  166. package/src/shade/renderer/geometry/virtual/build/level/vgeo_compute_group_boundary.js +123 -0
  167. package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.d.ts +26 -0
  168. package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.d.ts.map +1 -0
  169. package/src/shade/renderer/geometry/virtual/build/level/vgeo_error_bands.js +78 -0
  170. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts +24 -0
  171. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.d.ts.map +1 -0
  172. package/src/shade/renderer/geometry/virtual/build/level/vgeo_partition_into_groups.js +337 -0
  173. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts +29 -0
  174. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.d.ts.map +1 -0
  175. package/src/shade/renderer/geometry/virtual/build/level/vgeo_run_round.js +147 -0
  176. package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.d.ts +37 -0
  177. package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.d.ts.map +1 -0
  178. package/src/shade/renderer/geometry/virtual/build/level/vgeo_stitch_frontier.js +243 -0
  179. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts +29 -0
  180. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.d.ts.map +1 -0
  181. package/src/shade/renderer/geometry/virtual/build/level/vgeo_try_repack.js +117 -0
  182. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts +46 -0
  183. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts.map +1 -0
  184. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +45 -0
  185. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +64 -0
  186. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -0
  187. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +68 -0
  188. package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts +12 -7
  189. package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.d.ts.map +1 -1
  190. package/src/shade/renderer/geometry/virtual/build/mesh/VirtualGeometryMesh.js +33 -11
  191. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.d.ts +58 -0
  192. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.d.ts.map +1 -0
  193. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_layout.js +79 -0
  194. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.d.ts +39 -0
  195. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.d.ts.map +1 -0
  196. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_read.js +68 -0
  197. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.d.ts +53 -0
  198. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.d.ts.map +1 -0
  199. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_attribute_vector_write.js +243 -0
  200. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +24 -8
  201. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
  202. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +250 -25
  203. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts +12 -8
  204. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.d.ts.map +1 -1
  205. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.js +58 -50
  206. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +8 -1
  207. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
  208. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +18 -3
  209. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.d.ts +38 -0
  210. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.d.ts.map +1 -0
  211. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_resolve_attribute_weights.js +81 -0
  212. package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts +23 -5
  213. package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.d.ts.map +1 -1
  214. package/src/shade/renderer/geometry/virtual/build/partition/VGeoFaceGraph.js +28 -21
  215. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set.js +1 -1
  216. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.d.ts.map +1 -1
  217. package/src/shade/renderer/geometry/virtual/build/partition/vgeo_split_face_set_packed.js +224 -60
  218. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts +15 -0
  219. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.d.ts.map +1 -1
  220. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoGatheredFaces.js +17 -0
  221. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts +17 -0
  222. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.d.ts.map +1 -1
  223. package/src/shade/renderer/geometry/virtual/build/submesh/VGeoSubmesh.js +19 -0
  224. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts +10 -1
  225. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.d.ts.map +1 -1
  226. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_extract_submesh.js +103 -9
  227. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts +14 -2
  228. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.d.ts.map +1 -1
  229. package/src/shade/renderer/geometry/virtual/build/submesh/vgeo_gather_faces.js +38 -14
  230. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts +6 -2
  231. package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
  232. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +28 -5
  233. package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.d.ts +32 -0
  234. package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.d.ts.map +1 -0
  235. package/src/shade/renderer/geometry/virtual/build/vgeo_subtree_bounds.js +93 -0
  236. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +20 -6
  237. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
  238. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +22 -8
  239. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_corner.d.ts +16 -0
  240. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_corner.d.ts.map +1 -0
  241. package/src/shade/renderer/geometry/virtual/format/attribute/{vgeo_layers_copy_vertex.js → vgeo_layers_copy_corner.js} +8 -8
  242. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.d.ts +18 -7
  243. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.d.ts.map +1 -1
  244. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.js +19 -8
  245. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.d.ts +3 -3
  246. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.js +3 -3
  247. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.d.ts +27 -0
  248. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.d.ts.map +1 -0
  249. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_mesh_wedges.js +97 -0
  250. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.d.ts +7 -3
  251. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.d.ts.map +1 -1
  252. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.js +21 -11
  253. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.d.ts +21 -0
  254. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.d.ts.map +1 -0
  255. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET_V4.js +41 -0
  256. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +19 -1
  257. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
  258. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +20 -1
  259. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.d.ts +25 -0
  260. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.d.ts.map +1 -0
  261. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_DEFLATE.js +24 -0
  262. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.d.ts +5 -0
  263. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.d.ts.map +1 -1
  264. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.js +5 -0
  265. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.d.ts.map +1 -1
  266. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.js +5 -0
  267. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.d.ts +10 -3
  268. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.d.ts.map +1 -1
  269. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.js +37 -3
  270. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +21 -13
  271. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
  272. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +37 -13
  273. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.d.ts +8 -2
  274. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.d.ts.map +1 -1
  275. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.js +14 -2
  276. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +18 -0
  277. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
  278. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +19 -1
  279. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_OFFSET.js +6 -0
  280. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.d.ts +21 -0
  281. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.d.ts.map +1 -0
  282. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAX_LEVEL_COUNT.js +20 -0
  283. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.d.ts +9 -0
  284. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.d.ts.map +1 -1
  285. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.js +10 -1
  286. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +1 -2
  287. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +10 -3
  288. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.d.ts +20 -0
  289. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.d.ts.map +1 -0
  290. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET_V5.js +43 -0
  291. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts +4 -2
  292. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.d.ts.map +1 -1
  293. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +8 -4
  294. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  295. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +2 -2
  296. package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.d.ts +6 -4
  297. package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.d.ts.map +1 -1
  298. package/src/shade/renderer/geometry/virtual/format/read/VGeoDirectory.js +6 -4
  299. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +13 -2
  300. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
  301. package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +13 -2
  302. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +5 -1
  303. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -1
  304. package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +14 -1
  305. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -1
  306. package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +1 -0
  307. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.d.ts +4 -1
  308. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.d.ts.map +1 -1
  309. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_directory.js +53 -11
  310. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.d.ts.map +1 -1
  311. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_header.js +7 -3
  312. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts +12 -2
  313. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
  314. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +111 -33
  315. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts +6 -2
  316. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
  317. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +112 -42
  318. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts +2 -2
  319. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  320. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +51 -21
  321. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +385 -0
  322. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
  323. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +9 -0
  324. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
  325. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +34 -0
  326. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -1
  327. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +18 -0
  328. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  329. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +47 -19
  330. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.d.ts +1 -0
  331. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_OFFSET.js +22 -4
  332. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts +7 -2
  333. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.d.ts.map +1 -1
  334. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CLUSTER_ROW_WORDS.js +8 -3
  335. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
  336. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +10 -0
  337. package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
  338. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts +13 -11
  339. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.d.ts.map +1 -1
  340. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_slot_words.js +13 -11
  341. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
  342. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +4 -0
  343. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
  344. package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +3 -4
  345. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +6 -2
  346. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
  347. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +90 -12
  348. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts +22 -0
  349. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts.map +1 -0
  350. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js +21 -0
  351. package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
  352. package/src/shade/renderer/particles/shaders/shader_particle_emit.js +13 -8
  353. package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
  354. package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +3 -6
  355. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  356. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +4 -12
  357. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +0 -2
  358. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  359. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +4 -5
  360. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
  361. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +5 -3
  362. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.d.ts.map +1 -1
  363. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.js +11 -4
  364. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  365. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +4 -3
  366. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts.map +1 -1
  367. package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.js +3 -0
  368. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
  369. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +94 -90
  370. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  371. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +13 -5
  372. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  373. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +96 -89
  374. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts.map +1 -1
  375. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.js +3 -1
  376. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_two_way.d.ts.map +1 -1
  377. package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_two_way.js +4 -1
  378. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
  379. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +100 -89
  380. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.d.ts.map +1 -1
  381. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.js +31 -7
  382. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
  383. package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +1 -7
  384. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
  385. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +161 -153
  386. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
  387. package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +2 -7
  388. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  389. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +4 -8
  390. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
  391. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +5 -8
  392. package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts +25 -0
  393. package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.d.ts.map +1 -0
  394. package/src/shade/renderer/shadow/map/DEFAULT_SHADOWMAP_UPDATE_BUDGET.js +24 -0
  395. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +10 -0
  396. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  397. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +30 -21
  398. package/src/core/model/node-graph/visual/layout/LayoutBoxGraph.d.ts.map +0 -1
  399. package/src/core/model/node-graph/visual/layout/layout_assign_coordinates.d.ts.map +0 -1
  400. package/src/core/model/node-graph/visual/layout/layout_assign_layers.d.ts.map +0 -1
  401. package/src/core/model/node-graph/visual/layout/layout_break_cycles.d.ts.map +0 -1
  402. package/src/core/model/node-graph/visual/layout/layout_insert_lanes.d.ts.map +0 -1
  403. package/src/core/model/node-graph/visual/layout/layout_order_layers.d.ts.map +0 -1
  404. package/src/core/model/node-graph/visual/layout/layout_orient_links.d.ts.map +0 -1
  405. package/src/shade/playground/vgeo_viewer/cut_geometry.d.ts +0 -61
  406. package/src/shade/playground/vgeo_viewer/cut_geometry.d.ts.map +0 -1
  407. package/src/shade/playground/vgeo_viewer/main.d.ts.map +0 -1
  408. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts +0 -18
  409. package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +0 -1
  410. package/src/shade/playground/vgeo_viewer/select_cut.d.ts +0 -173
  411. package/src/shade/playground/vgeo_viewer/select_cut.d.ts.map +0 -1
  412. package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.d.ts +0 -52
  413. package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.d.ts.map +0 -1
  414. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.d.ts +0 -24
  415. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.d.ts.map +0 -1
  416. package/src/shade/renderer/geometry/virtual/build/VGeoLevel.d.ts +0 -32
  417. package/src/shade/renderer/geometry/virtual/build/VGeoLevel.d.ts.map +0 -1
  418. package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.d.ts +0 -59
  419. package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.d.ts.map +0 -1
  420. package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.d.ts +0 -44
  421. package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.d.ts.map +0 -1
  422. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.d.ts +0 -20
  423. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.d.ts.map +0 -1
  424. package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.d.ts +0 -73
  425. package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.d.ts.map +0 -1
  426. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts +0 -13
  427. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +0 -1
  428. package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.d.ts +0 -12
  429. package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.d.ts.map +0 -1
  430. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.d.ts +0 -36
  431. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.d.ts.map +0 -1
  432. package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.d.ts +0 -13
  433. package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.d.ts.map +0 -1
  434. package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.d.ts +0 -19
  435. package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.d.ts.map +0 -1
  436. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.d.ts +0 -29
  437. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.d.ts.map +0 -1
  438. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.d.ts +0 -31
  439. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.d.ts.map +0 -1
  440. package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.d.ts +0 -18
  441. package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.d.ts.map +0 -1
  442. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.d.ts +0 -14
  443. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.d.ts.map +0 -1
  444. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.d.ts +0 -12
  445. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.d.ts.map +0 -1
  446. package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.d.ts +0 -14
  447. package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.d.ts.map +0 -1
  448. package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.d.ts +0 -11
  449. package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.d.ts.map +0 -1
  450. package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.d.ts +0 -46
  451. package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.d.ts.map +0 -1
  452. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts +0 -22
  453. package/src/shade/renderer/geometry/virtual/build/vgeo_page_node_count.d.ts.map +0 -1
  454. package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.d.ts +0 -29
  455. package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.d.ts.map +0 -1
  456. package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.d.ts +0 -9
  457. package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.d.ts.map +0 -1
  458. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.d.ts +0 -10
  459. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.d.ts.map +0 -1
  460. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.d.ts +0 -15
  461. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.d.ts.map +0 -1
  462. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.d.ts +0 -16
  463. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.d.ts.map +0 -1
  464. package/src/shade/renderer/loader/gltf/fix_up_material_sides.d.ts +0 -10
  465. package/src/shade/renderer/loader/gltf/fix_up_material_sides.d.ts.map +0 -1
  466. package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.d.ts +0 -17
  467. package/src/shade/renderer/rasterize/expand/graph_triangles_filter_by_material_side.d.ts.map +0 -1
  468. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.d.ts +0 -3
  469. package/src/shade/renderer/rasterize/expand/shader_filter_triangle_by_material_side.d.ts.map +0 -1
  470. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts +0 -8
  471. package/src/shade/renderer/rasterize/forward/chunk_material_side_should_draw.d.ts.map +0 -1
  472. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_coordinates.d.ts +0 -0
  473. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_assign_layers.d.ts +0 -0
  474. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_break_cycles.d.ts +0 -0
  475. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_break_cycles.js +0 -0
  476. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_insert_lanes.d.ts +0 -0
  477. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_insert_lanes.js +0 -0
  478. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_order_layers.d.ts +0 -0
  479. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_order_layers.js +0 -0
  480. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_orient_links.d.ts +0 -0
  481. /package/src/core/{model/node-graph/visual/layout → graph/layout/layered}/layout_orient_links.js +0 -0
  482. /package/src/shade/playground/{vgeo_viewer → caldera}/main.d.ts +0 -0
@@ -0,0 +1,243 @@
1
+ import { assert } from "../../../../../../core/assert.js";
2
+ import { build_tangent_from_normal } from "../../../normals/build_tangent_from_normal.js";
3
+ import { VGEO_ATTRIBUTE } from "../../format/attribute/VGEO_ATTRIBUTE.js";
4
+
5
+ /**
6
+ * One vertex's widest channel record on its way into a layer.
7
+ * @type {Float32Array}
8
+ */
9
+ const scratch_record = new Float32Array(4);
10
+
11
+ /**
12
+ * The normal the tangent of the same vertex is squared up against.
13
+ * @type {Float32Array}
14
+ */
15
+ const scratch_normal = new Float32Array(3);
16
+
17
+ /**
18
+ * Frisvad's basis, when the carried tangent has degenerated.
19
+ * @type {Float32Array}
20
+ */
21
+ const scratch_fallback = new Float32Array(4);
22
+
23
+ /**
24
+ * Put the simplifier's vector back into the mesh's layers, and square up the frame it describes.
25
+ *
26
+ * **Nothing is *derived* for a pinned vertex.** That is the whole of what pinning means here and it
27
+ * is what lets a cut place two levels of detail side by side: a vertex two groups share must carry
28
+ * byte-identical values in both payloads, or the seam that is watertight in geometry shades as a
29
+ * crease (`ATTRIBUTE_PLAN_2026_09_18.md` §3, invariant 2).
30
+ *
31
+ * Its corners are still *written*, with what the vector says it already had, and that is not a
32
+ * loophole — it is the same guarantee under corner storage. A collapse re-points the victim's corners
33
+ * onto the survivor and they arrive carrying the victim's appearance, so leaving a pinned vertex
34
+ * alone no longer means leaving its value alone. The write is exact: those float32 records are where
35
+ * the vector was read from.
36
+ *
37
+ * Two channels need more than a copy:
38
+ *
39
+ * - **The normal** is renormalized. A blend of two unit vectors is not one, and a normal that is
40
+ * not unit is not a normal. Two exactly opposing normals blend to nothing, which has no direction
41
+ * to report and so keeps whatever the vertex already carried, the same answer
42
+ * {@link bt_mesh_compute_vertex_normals} gives for a vertex whose faces cancel.
43
+ * - **The colour** is clamped to `[0, 1]`. The value a collapse carries is a *fit*, not an average,
44
+ * and a fit extrapolates — which is right for a texture coordinate and wrong for a channel with a
45
+ * range. The encoder saturates anyway, so what this stops is not a corrupt word but the drift:
46
+ * an out-of-range value left in the layer is what the next level's field is fitted from, and it
47
+ * would walk further out at every round.
48
+ * - **The tangent** is re-orthogonalized against that normal and renormalized, and its fourth
49
+ * component — handedness, a discrete `±1` — is left exactly as the survivor had it, because it is
50
+ * a flag rather than a quantity and there is no average of `+1` and `-1`. A tangent that has
51
+ * blended its way onto the normal has no perpendicular component left to keep, and falls back to
52
+ * Frisvad's basis rather than to a zero vector the octahedral encoder cannot represent.
53
+ *
54
+ * @param {VirtualGeometryMesh} mesh mutated in place
55
+ * @param {{components: number, channels: {attribute: number, offset: number, count: number}[]}} layout
56
+ * from {@link vgeo_attribute_vector_layout}, the same one {@link vgeo_attribute_vector_read} used
57
+ * @param {Float64Array} values indexed by wedge id, as the simplifier left it
58
+ * @param {Float64Array|null} verbatim indexed by wedge id, as it was read — the simplifier does not
59
+ * take it and has nothing to say about it. `null` where the layout has no such component, which
60
+ * is every mesh whose tangent is derived rather than carried.
61
+ * @param {Set<number>} pinned vertex ids nothing may be *derived* for
62
+ * @param {BtWedgeSet} wedges which corners of each vertex shade as one, as the simplifier left it
63
+ *
64
+ * @author Alex Goldring
65
+ * @copyright Company Named Limited (c) 2026
66
+ */
67
+ export function vgeo_attribute_vector_write(mesh, layout, values, verbatim, pinned, wedges) {
68
+ assert.greaterThan(layout.components, 0, 'layout.components');
69
+
70
+ const topology = mesh.topology;
71
+
72
+ const components = layout.components;
73
+ const channels = layout.channels;
74
+
75
+ const normal_layer = mesh.layers[VGEO_ATTRIBUTE.NORMAL];
76
+
77
+ const carries_tangent = channels.some(
78
+ (channel) => channel.attribute === VGEO_ATTRIBUTE.TANGENT
79
+ );
80
+
81
+ /*
82
+ Over corners. The value is decided per *wedge* and stored per corner, so every corner of a wedge
83
+ gets the same one — and the frame fixups below, being functions of that value, agree corner for
84
+ corner without having to be told to. Two corners of one vertex in different wedges get different
85
+ ones, which is a hard edge, and is the entire point.
86
+ */
87
+ const loop_pool = topology.loops;
88
+
89
+ for (let loop = 0; loop < loop_pool.size; loop++) {
90
+ if (!loop_pool.is_allocated(loop)) {
91
+ continue;
92
+ }
93
+
94
+ const vertex = topology.loop_read_vertex(loop);
95
+
96
+ /*
97
+ A pinned vertex IS written, and writing it is what keeps it pinned. The vector holds what it
98
+ had -- nothing in the simplifier touches a restricted survivor's entry -- while its *corners*
99
+ do not, because a collapse re-points the victim's onto it and those arrive carrying the
100
+ victim's appearance. Writing the vector back over all of them is what puts that right, and it
101
+ is exact: the value came out of these same float32 records and goes back into them unchanged.
102
+
103
+ What it must not do is *derive* anything for a pinned vertex, so the fixups below are the
104
+ one thing that stays behind the flag.
105
+ */
106
+ const restore = pinned.has(vertex);
107
+
108
+ const wedge = wedges.find(wedges.of_loop[loop]);
109
+
110
+ const base = wedge * components;
111
+
112
+ for (const channel of channels) {
113
+ const layer = mesh.layers[channel.attribute];
114
+
115
+ // Read first: a channel the vector carries only part of — the tangent, whose handedness
116
+ // stays with the survivor — keeps the rest of its record this way.
117
+ layer.read(scratch_record, 0, loop);
118
+
119
+ for (let component = 0; component < channel.count; component++) {
120
+ const value = values[base + channel.offset + component];
121
+
122
+ assert.isFinite(value, 'carried attribute component');
123
+
124
+ scratch_record[channel.source + component] = value;
125
+ }
126
+
127
+ if (restore) {
128
+ layer.write(loop, scratch_record, 0);
129
+
130
+ continue;
131
+ }
132
+
133
+ if (channel.attribute === VGEO_ATTRIBUTE.NORMAL) {
134
+ normalize_in_place(scratch_record, layer, loop);
135
+ } else if (channel.attribute === VGEO_ATTRIBUTE.COLOR) {
136
+ for (let component = 0; component < channel.count; component++) {
137
+ scratch_record[component] = Math.min(1, Math.max(0, scratch_record[component]));
138
+ }
139
+ }
140
+
141
+ layer.write(loop, scratch_record, 0);
142
+ }
143
+
144
+ // After the loop rather than inside it, so the normal it squares up against is the one just
145
+ // written rather than whichever order the channel list happens to be in.
146
+ if (carries_tangent && !restore) {
147
+ orthogonalize_tangent(mesh, normal_layer, loop);
148
+ }
149
+
150
+ /*
151
+ Last, and over every corner whether the vertex is pinned or not. These components never
152
+ travelled through the fit and never will -- they are the survivor's, and putting them back
153
+ is what stops a corner a collapse donated from keeping the flag it arrived with.
154
+ */
155
+ if (verbatim === null) {
156
+ continue;
157
+ }
158
+
159
+ const verbatim_base = wedge * layout.verbatim_components;
160
+
161
+ for (const channel of layout.verbatim) {
162
+ const layer = mesh.layers[channel.attribute];
163
+
164
+ layer.read(scratch_record, 0, loop);
165
+
166
+ for (let component = 0; component < channel.count; component++) {
167
+ scratch_record[channel.source + component] =
168
+ verbatim[verbatim_base + channel.offset + component];
169
+ }
170
+
171
+ layer.write(loop, scratch_record, 0);
172
+ }
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Scale a channel record's first three components to unit length, leaving them alone when there is
178
+ * no direction there to scale.
179
+ *
180
+ * @param {Float32Array} record
181
+ * @param {BinaryDataLayer} layer the record came from, read again when the blend cancelled
182
+ * @param {number} loop
183
+ */
184
+ function normalize_in_place(record, layer, loop) {
185
+ const length = Math.hypot(record[0], record[1], record[2]);
186
+
187
+ if (length === 0) {
188
+ layer.read(record, 0, loop);
189
+
190
+ return;
191
+ }
192
+
193
+ record[0] /= length;
194
+ record[1] /= length;
195
+ record[2] /= length;
196
+ }
197
+
198
+ /**
199
+ * Square one vertex's tangent up against its normal.
200
+ *
201
+ * @param {VirtualGeometryMesh} mesh
202
+ * @param {BinaryDataLayer} normal_layer
203
+ * @param {number} loop
204
+ */
205
+ function orthogonalize_tangent(mesh, normal_layer, loop) {
206
+ const tangent_layer = mesh.layers[VGEO_ATTRIBUTE.TANGENT];
207
+
208
+ normal_layer.read(scratch_normal, 0, loop);
209
+ tangent_layer.read(scratch_record, 0, loop);
210
+
211
+ const nx = scratch_normal[0];
212
+ const ny = scratch_normal[1];
213
+ const nz = scratch_normal[2];
214
+
215
+ const dot = nx * scratch_record[0] + ny * scratch_record[1] + nz * scratch_record[2];
216
+
217
+ const tx = scratch_record[0] - nx * dot;
218
+ const ty = scratch_record[1] - ny * dot;
219
+ const tz = scratch_record[2] - nz * dot;
220
+
221
+ const length = Math.hypot(tx, ty, tz);
222
+
223
+ if (length === 0) {
224
+ // Nothing perpendicular survived: the carried tangent had blended its way onto the normal.
225
+ build_tangent_from_normal(nx, ny, nz, 0, scratch_fallback);
226
+
227
+ scratch_record[0] = scratch_fallback[0];
228
+ scratch_record[1] = scratch_fallback[1];
229
+ scratch_record[2] = scratch_fallback[2];
230
+ } else {
231
+ scratch_record[0] = tx / length;
232
+ scratch_record[1] = ty / length;
233
+ scratch_record[2] = tz / length;
234
+ }
235
+
236
+ // A frame the shading model cannot use and the octahedral encoder cannot represent would reach
237
+ // the asset as a silently wrong word.
238
+ assert.isFinite(scratch_record[0], 'tangent x');
239
+ assert.isFinite(scratch_record[1], 'tangent y');
240
+ assert.isFinite(scratch_record[2], 'tangent z');
241
+
242
+ tangent_layer.write(loop, scratch_record, 0);
243
+ }
@@ -1,10 +1,29 @@
1
1
  /**
2
- * Area-weighted vertex normals of a mesh, written into its normal channel.
2
+ * Area-weighted normals of a mesh, split at its creases, written into its normal channel.
3
3
  *
4
4
  * The geometry a mesh actually has is the answer for that mesh: carrying a surviving vertex's
5
5
  * original normal through a dozen collapses shades a coarse level by whichever vertices happened to
6
6
  * win, which is visibly wrong.
7
7
  *
8
+ * **Per corner group, not per vertex.** Averaging every face around a vertex is right for a surface
9
+ * and wrong for a corner. Two faces sharing an edge belong to the same group when the surface turns
10
+ * less than {@link VGEO_CREASE_ANGLE} across it; groups are the connected components that leaves,
11
+ * and each gets its own area-weighted average. A vertex on a smooth surface has exactly one, and
12
+ * this is then the pass it has always been. A box corner has three, and the eight vertices of a cube
13
+ * stop carrying a normal that is ninety degrees wrong for every face using it.
14
+ *
15
+ * Area weighting falls out of the arithmetic rather than being applied: Newell's normal *is* the
16
+ * face normal scaled by twice the area, so summing the raw face normals is the area-weighted sum.
17
+ * Which is the same thing {@link bt_mesh_compute_vertex_normals} does, one level down, for the whole
18
+ * vertex — and this reproduces its arithmetic step for step, down to the float32 face scratch and
19
+ * the reciprocal it scales by, so that a mesh without a crease in it comes out bit for bit the same
20
+ * as it did before any of this existed.
21
+ *
22
+ * An edge with anything other than two live triangles on it — a mesh boundary, a non-manifold fin —
23
+ * joins nothing. There is no pair of faces to ask the question of, and splitting is the conservative
24
+ * answer: it keeps each side's own normal rather than inventing an average across a join the mesh
25
+ * itself does not make.
26
+ *
8
27
  * **Except where the vertex was pinned.** A pinned vertex is one the step was forbidden to move, and
9
28
  * every group that touches it carries it — which is exactly what lets a cut place two levels of
10
29
  * detail side by side without a crack. That guarantee has to cover what the vertex *carries*, not
@@ -13,17 +32,14 @@
13
32
  * would disagree by however much the surface turns. So a pinned vertex keeps what it had, exactly
14
33
  * as it keeps where it was, and the frame stays continuous across every cut the DAG admits.
15
34
  *
16
- * The pass itself is {@link bt_mesh_compute_vertex_normals}; all this adds is the pin rule and
17
- * lifting its result out of the topology's own normal slots and into the format's normal attribute,
18
- * which is where the encoder reads from.
19
- *
20
- * @param {VirtualGeometryMesh} mesh whose normal layer is sized by the vertex pool and so carries a
21
- * slot for every live vertex by construction
35
+ * @param {VirtualGeometryMesh} mesh whose normal layer is sized by the loop pool and so carries a
36
+ * slot for every live corner by construction
22
37
  * @param {Set<number>} pinned vertex ids to leave exactly as they are; empty for a mesh nothing has
23
38
  * locked yet
39
+ * @param {number} [crease_angle] degrees; see {@link VGEO_CREASE_ANGLE}
24
40
  *
25
41
  * @author Alex Goldring
26
42
  * @copyright Company Named Limited (c) 2026
27
43
  */
28
- export function vgeo_compute_vertex_normals(mesh: VirtualGeometryMesh, pinned: Set<number>): void;
44
+ export function vgeo_compute_vertex_normals(mesh: VirtualGeometryMesh, pinned: Set<number>, crease_angle?: number): void;
29
45
  //# sourceMappingURL=vgeo_compute_vertex_normals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vgeo_compute_vertex_normals.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,+EANW,IAAI,MAAM,CAAC,QAyCrB"}
1
+ {"version":3,"file":"vgeo_compute_vertex_normals.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,+EAPW,IAAI,MAAM,CAAC,iBAEX,MAAM,QA4MhB"}
@@ -1,22 +1,55 @@
1
1
  import { assert } from "../../../../../../core/assert.js";
2
2
  import {
3
- bt_mesh_compute_vertex_normals
4
- } from "../../../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_normals.js";
3
+ NULL_POINTER
4
+ } from "../../../../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
5
+ import {
6
+ bt_face_compute_newell_normal
7
+ } from "../../../../../../core/geom/3d/topology/struct/binary/query/bt_face_compute_newell_normal.js";
5
8
  import { VGEO_ATTRIBUTE } from "../../format/attribute/VGEO_ATTRIBUTE.js";
9
+ import { VGEO_CREASE_ANGLE } from "./VGEO_CREASE_ANGLE.js";
6
10
 
7
11
  /**
8
- * One vertex's normal, on its way out of the topology's slot and into the format's channel.
12
+ * One corner's normal, on its way into the format's channel.
9
13
  * @type {Float32Array}
10
14
  */
11
15
  const scratch_normal = new Float32Array(3);
12
16
 
13
17
  /**
14
- * Area-weighted vertex normals of a mesh, written into its normal channel.
18
+ * One face's normal, scaled by twice its area.
19
+ *
20
+ * Float32 because {@link bt_mesh_compute_vertex_normals} accumulates from a float32 scratch, and
21
+ * this pass has to reproduce that sum exactly: on a mesh with no crease it *is* that pass, and the
22
+ * whole claim below is that only geometry with a crease or a seam in it moves.
23
+ * @type {Float32Array}
24
+ */
25
+ const scratch_face = new Float32Array(3);
26
+
27
+ /**
28
+ * Area-weighted normals of a mesh, split at its creases, written into its normal channel.
15
29
  *
16
30
  * The geometry a mesh actually has is the answer for that mesh: carrying a surviving vertex's
17
31
  * original normal through a dozen collapses shades a coarse level by whichever vertices happened to
18
32
  * win, which is visibly wrong.
19
33
  *
34
+ * **Per corner group, not per vertex.** Averaging every face around a vertex is right for a surface
35
+ * and wrong for a corner. Two faces sharing an edge belong to the same group when the surface turns
36
+ * less than {@link VGEO_CREASE_ANGLE} across it; groups are the connected components that leaves,
37
+ * and each gets its own area-weighted average. A vertex on a smooth surface has exactly one, and
38
+ * this is then the pass it has always been. A box corner has three, and the eight vertices of a cube
39
+ * stop carrying a normal that is ninety degrees wrong for every face using it.
40
+ *
41
+ * Area weighting falls out of the arithmetic rather than being applied: Newell's normal *is* the
42
+ * face normal scaled by twice the area, so summing the raw face normals is the area-weighted sum.
43
+ * Which is the same thing {@link bt_mesh_compute_vertex_normals} does, one level down, for the whole
44
+ * vertex — and this reproduces its arithmetic step for step, down to the float32 face scratch and
45
+ * the reciprocal it scales by, so that a mesh without a crease in it comes out bit for bit the same
46
+ * as it did before any of this existed.
47
+ *
48
+ * An edge with anything other than two live triangles on it — a mesh boundary, a non-manifold fin —
49
+ * joins nothing. There is no pair of faces to ask the question of, and splitting is the conservative
50
+ * answer: it keeps each side's own normal rather than inventing an average across a join the mesh
51
+ * itself does not make.
52
+ *
20
53
  * **Except where the vertex was pinned.** A pinned vertex is one the step was forbidden to move, and
21
54
  * every group that touches it carries it — which is exactly what lets a cut place two levels of
22
55
  * detail side by side without a crack. That guarantee has to cover what the vertex *carries*, not
@@ -25,51 +58,243 @@ const scratch_normal = new Float32Array(3);
25
58
  * would disagree by however much the surface turns. So a pinned vertex keeps what it had, exactly
26
59
  * as it keeps where it was, and the frame stays continuous across every cut the DAG admits.
27
60
  *
28
- * The pass itself is {@link bt_mesh_compute_vertex_normals}; all this adds is the pin rule and
29
- * lifting its result out of the topology's own normal slots and into the format's normal attribute,
30
- * which is where the encoder reads from.
31
- *
32
- * @param {VirtualGeometryMesh} mesh whose normal layer is sized by the vertex pool and so carries a
33
- * slot for every live vertex by construction
61
+ * @param {VirtualGeometryMesh} mesh whose normal layer is sized by the loop pool and so carries a
62
+ * slot for every live corner by construction
34
63
  * @param {Set<number>} pinned vertex ids to leave exactly as they are; empty for a mesh nothing has
35
64
  * locked yet
65
+ * @param {number} [crease_angle] degrees; see {@link VGEO_CREASE_ANGLE}
36
66
  *
37
67
  * @author Alex Goldring
38
68
  * @copyright Company Named Limited (c) 2026
39
69
  */
40
- export function vgeo_compute_vertex_normals(mesh, pinned) {
70
+ export function vgeo_compute_vertex_normals(mesh, pinned, crease_angle = VGEO_CREASE_ANGLE) {
41
71
  const normals = mesh.layers[VGEO_ATTRIBUTE.NORMAL];
42
72
 
43
73
  assert.notNull(normals, 'mesh normal channel');
44
74
 
45
75
  const topology = mesh.topology;
46
76
 
47
- bt_mesh_compute_vertex_normals(topology);
77
+ const face_pool = topology.faces;
78
+ const loop_pool = topology.loops;
79
+
80
+ /**
81
+ * Each face's normal scaled by twice its area, which is Newell's as it comes.
82
+ * @type {Float64Array}
83
+ */
84
+ const face_normal = new Float64Array(face_pool.size * 3);
85
+
86
+ /**
87
+ * Its length, so the angle test does not recompute one.
88
+ * @type {Float64Array}
89
+ */
90
+ const face_length = new Float64Array(face_pool.size);
91
+
92
+ for (let face = 0; face < face_pool.size; face++) {
93
+ if (!face_pool.is_allocated(face)) {
94
+ continue;
95
+ }
96
+
97
+ if (topology.face_read_loop(face) === NULL_POINTER) {
98
+ continue;
99
+ }
100
+
101
+ bt_face_compute_newell_normal(scratch_face, 0, topology, face);
102
+
103
+ const nx = scratch_face[0];
104
+ const ny = scratch_face[1];
105
+ const nz = scratch_face[2];
106
+
107
+ face_normal[face * 3] = nx;
108
+ face_normal[face * 3 + 1] = ny;
109
+ face_normal[face * 3 + 2] = nz;
48
110
 
49
- const vertex_pool = topology.vertices;
111
+ face_length[face] = Math.sqrt(nx * nx + ny * ny + nz * nz);
112
+ }
113
+
114
+ /**
115
+ * Union-find over corners: two corners of one vertex share a root when the surface between them
116
+ * never turned far enough to be a crease.
117
+ * @type {Uint32Array}
118
+ */
119
+ const group = new Uint32Array(loop_pool.size);
120
+
121
+ for (let loop = 0; loop < loop_pool.size; loop++) {
122
+ group[loop] = loop;
123
+ }
124
+
125
+ const smooth_cosine = Math.cos((crease_angle * Math.PI) / 180);
126
+
127
+ const edge_pool = topology.edges;
50
128
 
51
- for (let vertex = 0; vertex < vertex_pool.size; vertex++) {
52
- if (!vertex_pool.is_allocated(vertex)) {
53
- // a released slot's normal is whatever the vertex that used to live there left behind
129
+ for (let edge = 0; edge < edge_pool.size; edge++) {
130
+ if (!edge_pool.is_allocated(edge)) {
54
131
  continue;
55
132
  }
56
133
 
57
- if (pinned.has(vertex)) {
134
+ const first_loop = topology.edge_read_loop(edge);
135
+
136
+ if (first_loop === NULL_POINTER) {
58
137
  continue;
59
138
  }
60
139
 
61
- topology.vertex_read_normal(scratch_normal, 0, vertex);
140
+ let left = NULL_POINTER;
141
+ let right = NULL_POINTER;
142
+ let live = 0;
143
+
144
+ let loop = first_loop;
145
+
146
+ do {
147
+ const face = topology.loop_read_face(loop);
148
+
149
+ if (face !== NULL_POINTER && face_pool.is_allocated(face) && face_length[face] > 0) {
150
+ live++;
151
+
152
+ if (live === 1) {
153
+ left = loop;
154
+ } else if (live === 2) {
155
+ right = loop;
156
+ }
157
+ }
62
158
 
63
- const x = scratch_normal[0];
64
- const y = scratch_normal[1];
65
- const z = scratch_normal[2];
159
+ loop = topology.loop_read_radial_next(loop);
160
+ } while (loop !== first_loop && loop !== NULL_POINTER);
66
161
 
67
- if (x === 0 && y === 0 && z === 0) {
68
- // An isolated or fully degenerate vertex has no surface to take a normal from; leave
69
- // whatever it carried rather than inventing a direction.
162
+ if (live !== 2) {
70
163
  continue;
71
164
  }
72
165
 
73
- normals.write(vertex, scratch_normal, 0);
166
+ const left_face = topology.loop_read_face(left);
167
+ const right_face = topology.loop_read_face(right);
168
+
169
+ const cosine = (
170
+ face_normal[left_face * 3] * face_normal[right_face * 3]
171
+ + face_normal[left_face * 3 + 1] * face_normal[right_face * 3 + 1]
172
+ + face_normal[left_face * 3 + 2] * face_normal[right_face * 3 + 2]
173
+ ) / (face_length[left_face] * face_length[right_face]);
174
+
175
+ if (cosine < smooth_cosine) {
176
+ continue;
177
+ }
178
+
179
+ /*
180
+ A loop's edge runs from its own vertex to the next loop's, so on an edge's loop those two
181
+ are the edge's endpoints. Matching them up by vertex is what pairs the corner of one face
182
+ with the corner of the other *at the same point* -- the two faces may be wound oppositely,
183
+ which is exactly when the naive pairing would join the wrong ends.
184
+ */
185
+ const left_next = topology.loop_read_next(left);
186
+ const right_next = topology.loop_read_next(right);
187
+
188
+ if (topology.loop_read_vertex(left) === topology.loop_read_vertex(right)) {
189
+ join(group, left, right);
190
+ join(group, left_next, right_next);
191
+ } else {
192
+ join(group, left, right_next);
193
+ join(group, left_next, right);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Each group's area-weighted sum, accumulated at its root.
199
+ * @type {Float64Array}
200
+ */
201
+ const accumulated = new Float64Array(loop_pool.size * 3);
202
+
203
+ /*
204
+ Over faces and then their corners, which is the order `bt_mesh_compute_vertex_normals` sums in.
205
+ The order of a float64 sum is part of its answer, and reproducing it is what makes a mesh with
206
+ no crease byte-identical rather than merely equivalent.
207
+ */
208
+ for (let face = 0; face < face_pool.size; face++) {
209
+ if (!face_pool.is_allocated(face)) {
210
+ continue;
211
+ }
212
+
213
+ const first_loop = topology.face_read_loop(face);
214
+
215
+ if (first_loop === NULL_POINTER) {
216
+ continue;
217
+ }
218
+
219
+ const nx = face_normal[face * 3];
220
+ const ny = face_normal[face * 3 + 1];
221
+ const nz = face_normal[face * 3 + 2];
222
+
223
+ let loop = first_loop;
224
+
225
+ do {
226
+ const root = find(group, loop) * 3;
227
+
228
+ accumulated[root] += nx;
229
+ accumulated[root + 1] += ny;
230
+ accumulated[root + 2] += nz;
231
+
232
+ loop = topology.loop_read_next(loop);
233
+ } while (loop !== first_loop);
234
+ }
235
+
236
+ for (let loop = 0; loop < loop_pool.size; loop++) {
237
+ if (!loop_pool.is_allocated(loop)) {
238
+ continue;
239
+ }
240
+
241
+ if (pinned.has(topology.loop_read_vertex(loop))) {
242
+ continue;
243
+ }
244
+
245
+ const root = find(group, loop) * 3;
246
+
247
+ const x = accumulated[root];
248
+ const y = accumulated[root + 1];
249
+ const z = accumulated[root + 2];
250
+
251
+ const length = Math.sqrt(x * x + y * y + z * z);
252
+
253
+ if (length === 0) {
254
+ // An isolated corner, or a group whose faces cancel: no surface to take a normal from,
255
+ // so leave whatever it carried rather than inventing a direction.
256
+ continue;
257
+ }
258
+
259
+ // Scaled by the reciprocal rather than divided, because that is what
260
+ // `bt_mesh_compute_vertex_normals` does and `x * (1 / l)` is not `x / l`.
261
+ const scale = 1 / length;
262
+
263
+ scratch_normal[0] = x * scale;
264
+ scratch_normal[1] = y * scale;
265
+ scratch_normal[2] = z * scale;
266
+
267
+ normals.write(loop, scratch_normal, 0);
268
+ }
269
+ }
270
+
271
+ /**
272
+ * @param {Uint32Array} group
273
+ * @param {number} index
274
+ * @returns {number}
275
+ */
276
+ function find(group, index) {
277
+ let root = index;
278
+
279
+ while (group[root] !== root) {
280
+ group[root] = group[group[root]];
281
+
282
+ root = group[root];
283
+ }
284
+
285
+ return root;
286
+ }
287
+
288
+ /**
289
+ * @param {Uint32Array} group
290
+ * @param {number} a
291
+ * @param {number} b
292
+ */
293
+ function join(group, a, b) {
294
+ const root_a = find(group, a);
295
+ const root_b = find(group, b);
296
+
297
+ if (root_a !== root_b) {
298
+ group[root_b] = root_a;
74
299
  }
75
300
  }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Vertex tangents of a mesh, written into its tangent channel.
2
+ * Tangents of a mesh, written into its tangent channel.
3
3
  *
4
4
  * A tangent is a direction *in the texture parameterization*, so where the mesh carries a `UV0` this
5
- * is Lengyel's per-triangle solve accumulated per vertex and orthogonalized against the normal —
5
+ * is Lengyel's per-triangle solve accumulated per **wedge** and orthogonalized against the normal —
6
6
  * {@link geometry_build_tangents}, the same pass {@link Geometry#computeTangents} runs, so an asset
7
7
  * that goes through the virtual-geometry builder gets the frame it would have got anywhere else.
8
8
  * Where the mesh carries no UVs there is no parameterization to be tangent to, and the frame becomes
@@ -12,20 +12,24 @@
12
12
  * the format's flat default, which is parallel to the normal over a whole band of any closed
13
13
  * surface and degenerates the frame there.
14
14
  *
15
+ * **Per wedge, and that is not a re-indexing of a per-vertex solve.** Lengyel's accumulation is over
16
+ * the triangles that share a value, and at a chart boundary the two sides do not: their UVs run in
17
+ * different directions and averaging them gives a tangent that is tangent to neither. So the solve
18
+ * is fed a mesh whose *vertices are the wedges* — the same substitution the cluster gather makes,
19
+ * and for the same reason — and the answer comes back one per wedge, which is then written to every
20
+ * corner of it.
21
+ *
15
22
  * `pinned` carries the same meaning and the same reason as it does for
16
23
  * {@link vgeo_compute_vertex_normals}: a vertex two groups share must carry byte-identical values in
17
24
  * both, or the seam a cut is allowed to put between them shades as a crease.
18
25
  *
19
- * The flat arrays this builds are indexed by *vertex id*, holes and all, so a pool with released
20
- * slots needs no compaction and no remap — a released slot is simply a triangle corner nothing
21
- * names.
22
- *
23
- * @param {VirtualGeometryMesh} mesh whose tangent and normal layers are sized by the vertex pool
26
+ * @param {VirtualGeometryMesh} mesh whose tangent and normal layers are sized by the loop pool
24
27
  * @param {Set<number>} pinned vertex ids to leave exactly as they are; empty for a mesh nothing has
25
28
  * locked yet
29
+ * @param {BtWedgeSet} wedges which corners of each vertex shade as one
26
30
  *
27
31
  * @author Alex Goldring
28
32
  * @copyright Company Named Limited (c) 2026
29
33
  */
30
- export function vgeo_compute_vertex_tangents(mesh: VirtualGeometryMesh, pinned: Set<number>): void;
34
+ export function vgeo_compute_vertex_tangents(mesh: VirtualGeometryMesh, pinned: Set<number>, wedges: BtWedgeSet): void;
31
35
  //# sourceMappingURL=vgeo_compute_vertex_tangents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vgeo_compute_vertex_tangents.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,gFANW,IAAI,MAAM,CAAC,QAmGrB"}
1
+ {"version":3,"file":"vgeo_compute_vertex_tangents.d.ts","sourceRoot":"","sources":["../../../../../../../../src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_tangents.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,gFAPW,IAAI,MAAM,CAAC,4BA2GrB"}