@woosh/meep-engine 3.55.0 → 3.57.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 (650) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
  4. package/src/core/binary/BitSet.js +1 -1
  5. package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
  6. package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
  7. package/src/core/binary/FLOAT16_MAX.js +1 -0
  8. package/src/core/binary/base58/base58_encode.js +2 -2
  9. package/src/core/binary/type/TypeBuilder.js +1 -1
  10. package/src/core/bvh2/bvh3/BVH.js +1 -1
  11. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
  12. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
  13. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
  14. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
  15. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
  16. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
  17. package/src/core/collection/CuckooFilter.js +1 -1
  18. package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
  19. package/src/core/collection/array/isArrayEqual.js +33 -58
  20. package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
  21. package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
  22. package/src/core/collection/array/typed/float32_array_hash.js +38 -38
  23. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
  24. package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
  25. package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
  26. package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
  27. package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
  28. package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
  29. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
  30. package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
  31. package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
  32. package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
  33. package/src/core/collection/list/List.d.ts.map +1 -1
  34. package/src/core/collection/list/List.js +3 -19
  35. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  36. package/src/core/collection/table/RowFirstTable.js +4 -28
  37. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  38. package/src/core/debug/matchers/DescribeAs.js +62 -64
  39. package/src/core/function/FunctionCompiler.js +4 -4
  40. package/src/core/function/objectsEqual.d.ts.map +1 -1
  41. package/src/core/function/objectsEqual.js +3 -2
  42. package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
  43. package/src/core/geom/2d/bvh/BVH2D.js +4 -3
  44. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
  45. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  46. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
  47. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
  48. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
  49. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  50. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
  51. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
  52. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
  53. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
  54. package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
  55. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
  56. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
  57. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
  58. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
  59. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +20 -53
  60. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
  61. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
  62. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
  63. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
  64. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
  65. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
  66. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
  67. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
  68. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
  69. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  70. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
  71. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
  72. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
  73. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
  74. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
  75. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
  76. package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
  77. package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
  78. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
  79. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
  80. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
  81. package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
  82. package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
  83. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  84. package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
  85. package/src/core/geom/3d/shape/MeshShape3D.js +2 -56
  86. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  87. package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
  88. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  89. package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
  90. package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
  91. package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
  92. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
  93. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
  94. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
  95. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
  96. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
  97. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  98. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
  99. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
  100. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
  101. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  102. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
  103. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
  104. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
  105. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
  106. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
  107. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  108. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
  109. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  110. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
  111. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  112. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
  113. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  114. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +151 -194
  115. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
  116. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
  117. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  118. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
  119. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
  120. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
  121. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  122. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
  123. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
  124. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
  125. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
  126. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
  127. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +8 -14
  128. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
  129. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +36 -82
  130. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  131. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
  132. package/src/core/geom/ConicRay.d.ts.map +1 -1
  133. package/src/core/geom/ConicRay.js +230 -237
  134. package/src/core/localization/LocaleDataset.d.ts +6 -0
  135. package/src/core/localization/LocaleDataset.d.ts.map +1 -1
  136. package/src/core/localization/LocaleDataset.js +48 -37
  137. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  138. package/src/core/localization/LocalizationEngine.js +3 -2
  139. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  140. package/src/core/math/lookup/ParameterLookupTable.js +3 -1
  141. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  142. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
  143. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
  144. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  145. package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
  146. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
  147. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  148. package/src/core/model/DebouncedObservedBoolean.js +1 -1
  149. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  150. package/src/core/model/node-graph/node/NodeInstance.js +2 -7
  151. package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
  152. package/src/core/model/object/optional_equality.d.ts +3 -3
  153. package/src/core/model/object/optional_equality.d.ts.map +1 -1
  154. package/src/core/model/object/optional_equality.js +10 -27
  155. package/src/core/model/object/write_property.js +1 -1
  156. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
  157. package/src/core/primitives/strings/string_compute_byte_size.d.ts +3 -3
  158. package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +1 -1
  159. package/src/core/primitives/strings/string_compute_byte_size.js +8 -21
  160. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  161. package/src/core/process/executor/ConcurrentExecutor.js +14 -2
  162. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
  163. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
  164. package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
  165. package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
  166. package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
  167. package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
  168. package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
  169. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  170. package/src/engine/ecs/EntityComponentDataset.js +4 -1
  171. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
  172. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
  173. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
  174. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  175. package/src/engine/ecs/transform/Transform64.d.ts +21 -0
  176. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  177. package/src/engine/ecs/transform/Transform64.js +26 -0
  178. package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  179. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  180. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  181. package/src/engine/graphics3/WaterSystem.js +2 -1
  182. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  183. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  184. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  185. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  186. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  187. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  188. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  189. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  190. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  191. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  192. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  193. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  194. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  195. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  196. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  197. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  198. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  199. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  200. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  201. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  202. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  203. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  204. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  205. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  206. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  207. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  208. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  209. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  210. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  211. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  212. package/src/engine/navigation/ecs/components/Path.js +2 -1
  213. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  214. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  215. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  216. package/src/engine/physics/body/SolverBodyState.js +2 -6
  217. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  218. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  219. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  220. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  221. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  222. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  223. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  224. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  225. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  226. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  227. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  228. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  229. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  230. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  231. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  232. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  233. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  234. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  235. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  236. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  237. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  238. package/src/engine/save/StorageBackedList.d.ts +5 -0
  239. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  240. package/src/engine/save/StorageBackedList.js +161 -144
  241. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  242. package/src/engine/simulation/Ticker.js +394 -391
  243. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  244. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  245. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  246. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  247. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  248. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  249. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  250. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  251. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  252. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  253. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  254. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  255. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  256. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  257. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  258. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  259. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  260. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  261. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  262. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  263. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  264. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  265. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  266. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  267. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  268. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  269. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  270. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  271. package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
  272. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  273. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  274. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  275. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  276. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  277. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  278. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  279. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  280. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  281. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  282. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  283. package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
  284. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  285. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  286. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
  287. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  288. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  289. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  290. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  291. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  292. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  293. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  294. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  295. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  296. package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
  297. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  298. package/src/generation/foliage/asset/TreeAsset.js +6 -0
  299. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  300. package/src/generation/foliage/asset/generate_tree.js +23 -6
  301. package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
  302. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  303. package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
  304. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  305. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  306. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  307. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  308. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  309. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  310. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  311. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  312. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  313. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  314. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  315. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  316. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  317. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  318. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  319. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  320. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  321. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  322. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  323. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  324. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  325. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  326. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  327. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  328. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  329. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  330. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  331. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  332. package/src/generation/foliage/config/LeafLobation.js +14 -0
  333. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  334. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  335. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  336. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  337. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  338. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  339. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
  340. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  341. package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
  342. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  343. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  344. package/src/generation/foliage/config/ShootSystemRule.js +316 -0
  345. package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
  346. package/src/generation/foliage/config/TreeLODConfig.js +1 -1
  347. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
  348. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  349. package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
  350. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  351. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  352. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  353. package/src/generation/foliage/index.d.ts +19 -2
  354. package/src/generation/foliage/index.js +63 -44
  355. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  356. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  357. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  358. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  359. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  360. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  361. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
  362. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  363. package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
  364. package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
  365. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  366. package/src/generation/foliage/material/foliage_tile.js +286 -0
  367. package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
  368. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  369. package/src/generation/foliage/material/leaf_geometry.js +528 -0
  370. package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
  371. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  372. package/src/generation/foliage/material/make_foliage_material.js +356 -605
  373. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
  374. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  375. package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
  376. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  377. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  378. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  379. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  380. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
  381. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
  382. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  383. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
  384. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  385. package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
  386. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
  387. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  388. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
  389. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  390. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  391. package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
  392. package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
  393. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  394. package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
  395. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
  396. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  397. package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
  398. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  399. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  400. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  401. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  402. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  403. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  404. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  405. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  406. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  407. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  408. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  409. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  410. package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
  411. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  412. package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
  413. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
  414. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  415. package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
  416. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
  417. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  418. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
  419. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
  420. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  421. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
  422. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  423. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  424. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  425. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  426. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  427. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  428. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  429. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
  430. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
  431. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  432. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
  433. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  434. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  435. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  436. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  437. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  438. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  439. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  440. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  441. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  442. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  443. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  444. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  445. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  446. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  447. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  448. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  449. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  450. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  451. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  452. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  453. package/src/shade/playground/foliage_wind/index.html +6 -0
  454. package/src/shade/playground/foliage_wind/main.js +14 -0
  455. package/src/shade/renderer/Renderer.d.ts +5 -0
  456. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  457. package/src/shade/renderer/Renderer.js +25 -2
  458. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  459. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  460. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  461. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  462. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  463. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  464. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  465. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  466. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  467. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  468. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
  469. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  470. package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
  471. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  472. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  473. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  474. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  475. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  476. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
  477. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  478. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  479. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  480. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  481. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  482. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  483. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  484. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  485. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  486. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  487. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  488. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  489. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  490. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  491. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  492. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  493. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  494. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  495. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  496. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  497. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  498. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  499. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  500. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  501. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  502. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  503. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  504. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  505. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  506. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  507. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  508. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  509. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  510. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  511. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  512. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
  513. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  514. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  515. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  516. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  517. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  518. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  519. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  520. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  521. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  522. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  523. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  524. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  525. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  526. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  527. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  528. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  529. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  530. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  531. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  532. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  533. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  534. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  535. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  536. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  537. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  538. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  539. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  540. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  541. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +2 -1
  542. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  543. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  544. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +2 -2
  545. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  546. package/src/shade/renderer/particles/graph_particles_avboit.js +4 -9
  547. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  548. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  549. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  550. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  551. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  552. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  553. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  554. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  555. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  556. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  557. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  558. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  559. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  560. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  561. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  562. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  563. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  564. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  565. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  566. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  567. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  568. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  569. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  570. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  571. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  572. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  573. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  574. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  575. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  576. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  577. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  578. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  579. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  580. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  581. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  582. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  583. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  584. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  585. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  586. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  587. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  588. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  589. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  590. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  591. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  592. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  593. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  594. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  595. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  596. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  597. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  598. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  599. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  600. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  601. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  602. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  603. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  604. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  605. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  606. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  607. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  608. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  609. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  610. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  611. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  612. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  613. package/src/shade/renderer/view/GPUViewContext.d.ts +0 -14
  614. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  615. package/src/shade/renderer/view/GPUViewContext.js +0 -29
  616. package/src/shade/renderer/view/ViewManager.d.ts +1 -1
  617. package/src/shade/renderer/view/ViewManager.js +1 -1
  618. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +40 -3
  619. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  620. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +660 -583
  621. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  622. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  623. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  624. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  625. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  626. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  627. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  628. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
  629. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  630. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  631. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
  632. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  633. package/src/shade/wgsl/validate_wgsl_source.js +27 -1
  634. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  635. package/src/view/controller/controls/ListController.js +118 -113
  636. package/src/view/controller/controls/Vector1Control.js +97 -97
  637. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  638. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  639. package/src/view/elements/image/SvgImageView.js +92 -90
  640. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  641. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  642. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  643. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  644. package/src/engine/network/PriorityFetch.d.ts +0 -59
  645. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  646. package/src/engine/network/PriorityFetch.js +0 -193
  647. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
  648. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.d.ts +0 -2
  649. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.d.ts.map +0 -1
  650. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.js +0 -1
@@ -1,605 +1,356 @@
1
- import AABB2 from "../../../core/geom/2d/aabb/AABB2.js";
2
- import { pack_max_rectangles } from "../../../core/geom/packing/max-rect/pack_max_rectangles.js";
3
- import { clamp } from "../../../core/math/clamp.js";
4
- import { lerp } from "../../../core/math/lerp.js";
5
- import { sdnoise3_array } from "../../../core/math/noise/sdnoise.js";
6
- import { seededRandom } from "../../../core/math/random/seededRandom.js";
7
- import { smoothStep } from "../../../core/math/smoothStep.js";
8
- import { Sampler2D } from "../../../engine/graphics/texture/sampler/Sampler2D.js";
9
- import { ShadeDrawSide } from "../../../shade/renderer/material/ShadeDrawSide.js";
10
- import { StandardShadeMaterial } from "../../../shade/renderer/material/StandardShadeMaterial.js";
11
- import { TransparencyMode } from "../../../shade/renderer/material/TransparencyMode.js";
12
- import { ColorSpace } from "../../../shade/renderer/texture/ColorSpace.js";
13
- import { ShadeTexture } from "../../../shade/renderer/texture/ShadeTexture.js";
14
- import { TextureFilterType } from "../../../shade/renderer/texture/TextureFilterType.js";
15
- import { TextureWrapType } from "../../../shade/renderer/texture/TextureWrapType.js";
16
- import { AlphaMode } from "../../../shade/renderer/texture/source/AlphaMode.js";
17
- import { ShadeImage } from "../../../shade/renderer/texture/source/ShadeImage.js";
18
- import { FoliageMaterialConfig } from "../config/FoliageMaterialConfig.js";
19
-
20
- const SCRATCH_NOISE = new Float32Array(4);
21
-
22
- /**
23
- * Packs `variant_count` square foliage card tiles of size `resolution x resolution` into a 2D atlas
24
- * using the engine's `MaxRectanglesPacker` (`pack_max_rectangles`), returning the atlas dimensions,
25
- * pixel-space `AABB2` boxes, and normalized `[u0, v0, u1, v1]` UV rectangles.
26
- *
27
- * @param {number} [resolution=128]
28
- * @param {number} [variant_count=4]
29
- * @returns {{
30
- * resolution: number,
31
- * variant_count: number,
32
- * atlas_w: number,
33
- * atlas_h: number,
34
- * boxes: AABB2[],
35
- * uv_rects: Float32Array
36
- * }}
37
- */
38
- export function compute_foliage_variant_atlas_layout(resolution = 128, variant_count = 4) {
39
- const res = Math.max(16, resolution | 0);
40
- const count = clamp(variant_count | 0, 1, 16);
41
- const cols = Math.max(1, Math.ceil(Math.sqrt(count)));
42
- const rows = Math.max(1, Math.ceil(count / cols));
43
- const atlas_w = cols * res;
44
- const atlas_h = rows * res;
45
-
46
- /** @type {AABB2[]} */
47
- const boxes = new Array(count);
48
- for (let k = 0; k < count; k++) {
49
- boxes[k] = new AABB2(0, 0, res, res);
50
- }
51
-
52
- const packed = pack_max_rectangles(atlas_w, atlas_h, boxes);
53
- if (!packed) {
54
- // Deterministic grid fallback if custom non-uniform boxes are ever used
55
- for (let k = 0; k < count; k++) {
56
- const c = k % cols;
57
- const r = Math.floor(k / cols);
58
- boxes[k].set(c * res, r * res, (c + 1) * res, (r + 1) * res);
59
- }
60
- }
61
-
62
- const uv_rects = new Float32Array(count * 4);
63
- for (let k = 0; k < count; k++) {
64
- const b = boxes[k];
65
- const k4 = k * 4;
66
- uv_rects[k4] = b.x0 / atlas_w;
67
- uv_rects[k4 + 1] = b.y0 / atlas_h;
68
- uv_rects[k4 + 2] = b.x1 / atlas_w;
69
- uv_rects[k4 + 3] = b.y1 / atlas_h;
70
- }
71
-
72
- return {
73
- resolution: res,
74
- variant_count: count,
75
- atlas_w,
76
- atlas_h,
77
- boxes,
78
- uv_rects
79
- };
80
- }
81
-
82
- /**
83
- * Evaluates a single leaflet SDF, ontogenetic morphology, and venation relief in local leaflet
84
- * coordinates `(lx, ly)` where `ly` in `[0, 1]` runs from petiole base to leaflet tip and `lx`
85
- * in `[-0.5, 0.5]` runs across width.
86
- *
87
- * @param {number} lx
88
- * @param {number} ly
89
- * @param {string} shape `"ovate" | "lobed" | "serrated" | "palmate" | "needle" | "frond"`
90
- * @param {number} mu_k ontogenetic maturity in `[0, 1]` (`0` = juvenile, `1` = mature)
91
- * @param {number} shape_var ontogenetic morphology variation strength `[0, 1]`
92
- * @param {number} vein_contrast ontogenetic venation & bullation contrast `[0, 1]`
93
- * @returns {{ mask: number, vein: number, height: number, edge_norm: number }}
94
- */
95
- function evaluate_leaflet(lx, ly, shape, mu_k, shape_var, vein_contrast) {
96
- if (ly < -0.05 || ly > 1.05) {
97
- return { mask: 0.0, vein: 0.0, height: 0.0, edge_norm: 0.0 };
98
- }
99
-
100
- const t = clamp(ly, 0.0, 1.0);
101
- const ax = Math.abs(lx);
102
-
103
- // Juvenile leaves expand longitudinally before full lateral blade expansion (narrower, more acuminate)
104
- const width_scale = lerp(1.0 - 0.26 * shape_var, 1.0 + 0.08 * shape_var, mu_k);
105
- const lobe_scale = lerp(1.0 - 0.45 * shape_var, 1.0 + 0.15 * shape_var, mu_k);
106
- const profile_exp = lerp(0.84, 0.68, mu_k);
107
-
108
- let half_w = 0.34 * width_scale * Math.sin(Math.PI * Math.pow(t, profile_exp));
109
-
110
- switch (shape) {
111
- case "lobed": {
112
- // Oak-like rounded lobes along margin deepen as lamina matures
113
- const lobe = 1.0 + 0.28 * lobe_scale * Math.sin(t * Math.PI * 7.0 - 0.6) * Math.sin(Math.PI * t);
114
- half_w *= lobe;
115
- break;
116
- }
117
- case "serrated": {
118
- // Birch/elm sawtooth serration
119
- const tooth = (t * 14.0) % 1.0;
120
- half_w *= (1.0 - 0.12 * lobe_scale + 0.16 * lobe_scale * (1.0 - tooth));
121
- break;
122
- }
123
- case "palmate": {
124
- // Maple-like broader lobed palmate blade
125
- const lobe = 1.0 + 0.32 * lobe_scale * Math.cos(t * Math.PI * 5.0);
126
- half_w = 0.40 * width_scale * Math.sin(Math.PI * Math.pow(t, lerp(0.76, 0.62, mu_k))) * lobe;
127
- break;
128
- }
129
- case "needle": {
130
- // Slender conifer needle
131
- half_w = 0.065 * lerp(0.85, 1.05, mu_k) * (1.0 - 0.65 * t * t);
132
- break;
133
- }
134
- case "frond": {
135
- // Long tapering willow/palm/fern pinna
136
- half_w = 0.19 * width_scale * Math.sin(Math.PI * Math.pow(t, lerp(0.70, 0.56, mu_k)));
137
- break;
138
- }
139
- case "ovate":
140
- default:
141
- break;
142
- }
143
-
144
- if (ax > half_w + 0.04) {
145
- return { mask: 0.0, vein: 0.0, height: 0.0, edge_norm: 0.0 };
146
- }
147
-
148
- const edge_dist = half_w - ax;
149
- const mask = smoothStep(-0.015, 0.018, edge_dist);
150
- if (mask <= 0.0) {
151
- return { mask: 0.0, vein: 0.0, height: 0.0, edge_norm: 0.0 };
152
- }
153
-
154
- const inv_hw = 1.0 / Math.max(1e-3, half_w);
155
- const edge_norm = clamp(edge_dist * inv_hw, 0.0, 1.0);
156
-
157
- // Midrib + herringbone secondary veins (sharper and more lignified on mature leaves)
158
- const midrib_sharp = lerp(700.0, 1050.0, mu_k);
159
- const midrib = Math.exp(-ax * ax * midrib_sharp) * (1.0 - 0.58 * t);
160
- const sec_coord = (t * 9.0 - ax * 6.5);
161
- const sec_frac = sec_coord - Math.floor(sec_coord);
162
- const sec_sharp = lerp(36.0, 80.0, mu_k * vein_contrast + 0.25);
163
- const sec_amp = lerp(0.28, 0.54, mu_k);
164
- const sec_vein = Math.exp(-Math.pow(sec_frac - 0.5, 2.0) * sec_sharp)
165
- * smoothStep(0.0, half_w, half_w - ax * 0.85)
166
- * sec_amp;
167
-
168
- const vein_relief = lerp(1.0 - 0.62 * vein_contrast, 1.0 + 0.34 * vein_contrast, mu_k);
169
- const vein = clamp((midrib + sec_vein) * vein_relief, 0.0, 1.0);
170
-
171
- // Lamina pillow camber across width + mature interveinal mesophyll bullation + vein ridge
172
- const camber = Math.sqrt(Math.max(0.0, 1.0 - Math.pow(ax * inv_hw, 2.0))) * lerp(0.45, 0.68, mu_k);
173
- const bullation = Math.sin(sec_frac * Math.PI)
174
- * smoothStep(0.0, 0.65, edge_norm)
175
- * (1.0 - midrib)
176
- * lerp(0.02, 0.26, mu_k)
177
- * vein_contrast;
178
- const height = (camber + bullation + vein * 0.40) * mask;
179
-
180
- return { mask, vein, height, edge_norm };
181
- }
182
-
183
- /**
184
- * Synthesizes a turn-key procedural PBR cutout `StandardShadeMaterial` (`TransparencyMode.AlphaTested`,
185
- * `ShadeDrawSide.Double`) for botanical foliage cards, packing `config.variant_count` ontogenetic and
186
- * biochemically senescent leaf cluster variants into the texture atlas via `MaxRectanglesPacker`
187
- * (`pack_max_rectangles`), with dilated straight-alpha Albedo (`AlphaMode.Straight`, `ColorSpace.SRGB`),
188
- * 2-channel Normal map (`ColorSpace.LinearSRGB`), and ORM (`ColorSpace.LinearSRGB`).
189
- *
190
- * @param {FoliageMaterialConfig|Object} [config]
191
- * @param {number} [seed=1]
192
- * @returns {StandardShadeMaterial}
193
- */
194
- export function make_foliage_material(config = new FoliageMaterialConfig(), seed = 1) {
195
- const cfg = config && config.isFoliageMaterialConfig ? config : FoliageMaterialConfig.from(config);
196
- const layout = compute_foliage_variant_atlas_layout(cfg.resolution, cfg.variant_count);
197
- const res = layout.resolution;
198
- const variant_count = layout.variant_count;
199
- const atlas_w = layout.atlas_w;
200
- const atlas_h = layout.atlas_h;
201
- const boxes = layout.boxes;
202
-
203
- const rng = seededRandom((seed ^ 0x7F4A7C15) | 0);
204
-
205
- const albedo_sampler = Sampler2D.uint8(4, atlas_w, atlas_h);
206
- const normal_sampler = Sampler2D.uint8(2, atlas_w, atlas_h);
207
- const orm_sampler = Sampler2D.uint8(4, atlas_w, atlas_h);
208
-
209
- const albedo_data = albedo_sampler.data;
210
- const normal_data = normal_sampler.data;
211
- const orm_data = orm_sampler.data;
212
-
213
- const height_field = new Float32Array(atlas_w * atlas_h);
214
- const shape = cfg.leaf_shape || "lobed";
215
- const leaflet_count = Math.max(1, cfg.leaflets_per_cluster | 0);
216
- const base_rough = clamp(cfg.roughness, 0.1, 1.0);
217
- const vein_str = clamp(cfg.vein_strength, 0.0, 1.0);
218
-
219
- // Ontogeny & first-principles biochemical senescence parameters
220
- const juv_shift = clamp(cfg.juvenile_color_shift ?? 0.38, 0.0, 1.0);
221
- const juv_antho = clamp(cfg.juvenile_anthocyanin ?? 0.08, 0.0, 1.0);
222
- const shape_var = clamp(cfg.ontogeny_shape_variation ?? 0.35, 0.0, 1.0);
223
- const vein_contrast = clamp(cfg.ontogeny_vein_contrast ?? 0.55, 0.0, 1.0);
224
-
225
- // Honour both first-principles `senescence` and legacy `autumn_tint`
226
- const senescence = clamp(Math.max(cfg.senescence ?? 0.0, cfg.autumn_tint ?? 0.0), 0.0, 1.0);
227
- const car_density = clamp(cfg.carotenoid_density ?? 0.75, 0.0, 1.0);
228
- const antho_pot = clamp(cfg.anthocyanin_potential ?? 0.35, 0.0, 1.0);
229
- const tannin_ox = clamp(cfg.tannin_oxidation ?? 0.25, 0.0, 1.0);
230
-
231
- const p_r = cfg.primary_color.r;
232
- const p_g = cfg.primary_color.g;
233
- const p_b = cfg.primary_color.b;
234
- const s_r = cfg.secondary_color.r;
235
- const s_g = cfg.secondary_color.g;
236
- const s_b = cfg.secondary_color.b;
237
-
238
- // Pre-fill entire atlas with dilated base RGB (alpha = 0) and neutral normal/ORM so any
239
- // unused rectangle cells (e.g., when variant_count = 3 or 5) still carry valid dilated RGB.
240
- const fill_r = clamp(Math.round(Math.max(0.04, p_r) * 255), 1, 255);
241
- const fill_g = clamp(Math.round(Math.max(0.04, p_g) * 255), 1, 255);
242
- const fill_b = clamp(Math.round(Math.max(0.02, p_b) * 255), 1, 255);
243
- const fill_rough = clamp(Math.round(base_rough * 255), 0, 255);
244
- const total_texels = atlas_w * atlas_h;
245
- for (let p = 0; p < total_texels; p++) {
246
- const i4 = p * 4;
247
- albedo_data[i4] = fill_r;
248
- albedo_data[i4 + 1] = fill_g;
249
- albedo_data[i4 + 2] = fill_b;
250
- albedo_data[i4 + 3] = 0;
251
-
252
- const i2 = p * 2;
253
- normal_data[i2] = 128;
254
- normal_data[i2 + 1] = 128;
255
-
256
- orm_data[i4] = 255;
257
- orm_data[i4 + 1] = fill_rough;
258
- orm_data[i4 + 2] = 0;
259
- orm_data[i4 + 3] = 255;
260
- }
261
-
262
- const anchor_u = clamp(cfg.stem_anchor_u ?? 0.5, 0.1, 0.9);
263
- const anchor_v = clamp(cfg.stem_anchor_v ?? 0.0, 0.0, 0.25);
264
- const min_stem_half_w = Math.max(0.022, 1.5 / res);
265
-
266
- for (let v_idx = 0; v_idx < variant_count; v_idx++) {
267
- const box = boxes[v_idx];
268
- const tile_x0 = box.x0;
269
- const tile_y0 = box.y0;
270
-
271
- // Ontogenetic coordinate mu_k in [0, 1]: 0 = juvenile apical flush, 1 = mature basal foliage
272
- const mu_k = variant_count > 1 ? v_idx / (variant_count - 1) : 0.65;
273
- const ox = (rng() - 0.5) * 150.0 + v_idx * 37.3;
274
- const oy = (rng() - 0.5) * 150.0 + v_idx * 53.7;
275
-
276
- // Ontogenetic cluster geometry scaling: juvenile shoots are slightly more forward-cupped and compact
277
- const angle_scale = lerp(1.0 - 0.22 * shape_var, 1.0 + 0.06 * shape_var, mu_k);
278
- const len_scale = lerp(1.0 - 0.14 * shape_var, 1.0 + 0.04 * shape_var, mu_k);
279
-
280
- const leaflets = [];
281
- if (shape === "palmate") {
282
- const count = Math.max(3, leaflet_count | 1);
283
- for (let i = 0; i < count; i++) {
284
- const frac = (i / (count - 1)) * 2.0 - 1.0; // [-1, 1]
285
- const angle = frac * 1.05 * angle_scale;
286
- const scale = (1.0 - 0.32 * Math.abs(frac)) * 0.76 * len_scale;
287
- leaflets.push({
288
- ox: anchor_u,
289
- oy: anchor_v + 0.08,
290
- dir_x: Math.sin(angle),
291
- dir_y: Math.cos(angle),
292
- length: scale,
293
- width: scale * 0.9
294
- });
295
- }
296
- } else if (shape === "needle") {
297
- const pairs = Math.max(4, leaflet_count);
298
- for (let i = 0; i < pairs; i++) {
299
- const v_stem = anchor_v + 0.04 + (i / pairs) * 0.74;
300
- for (const side of [-1, 1]) {
301
- const angle = side * (0.45 + 0.25 * (1.0 - i / pairs)) * angle_scale;
302
- const len = 0.36 * (1.0 - 0.35 * (i / pairs)) * len_scale;
303
- leaflets.push({
304
- ox: anchor_u,
305
- oy: v_stem,
306
- dir_x: Math.sin(angle),
307
- dir_y: Math.cos(angle),
308
- length: len,
309
- width: len
310
- });
311
- }
312
- }
313
- leaflets.push({
314
- ox: anchor_u,
315
- oy: anchor_v + 0.72,
316
- dir_x: 0.0,
317
- dir_y: 1.0,
318
- length: 0.26 * len_scale,
319
- width: 0.26 * len_scale
320
- });
321
- } else {
322
- const pairs = Math.max(1, Math.floor(leaflet_count / 2));
323
- for (let p = 0; p < pairs; p++) {
324
- const u_p = (p + 0.35) / (pairs + 0.35);
325
- const v_stem = anchor_v + 0.04 + u_p * 0.56;
326
- const angle_mag = lerp(0.95, 0.55, u_p) * angle_scale;
327
- const len = lerp(0.40, 0.30, u_p) * len_scale;
328
- for (const side of [-1, 1]) {
329
- const angle = side * angle_mag;
330
- leaflets.push({
331
- ox: anchor_u,
332
- oy: v_stem,
333
- dir_x: Math.sin(angle),
334
- dir_y: Math.cos(angle),
335
- length: len,
336
- width: len * 0.95
337
- });
338
- }
339
- }
340
- leaflets.push({
341
- ox: anchor_u,
342
- oy: anchor_v + 0.56,
343
- dir_x: 0.0,
344
- dir_y: 1.0,
345
- length: 0.42 * len_scale,
346
- width: 0.40 * len_scale
347
- });
348
- }
349
-
350
- // Ontogenetic chlorophyll accumulation (juvenile protochlorophyllide lag -> lighter yellow-green)
351
- const juv_factor = (1.0 - mu_k) * juv_shift;
352
- // Staggered variant senescence progression across the atlas so autumn crowns exhibit natural leaf-to-leaf diversity
353
- const sigma_k = senescence > 0.0
354
- ? clamp(senescence * (0.80 + 0.36 * Math.abs(mu_k - 0.35)) + senescence * senescence * 0.12, 0.0, 1.0)
355
- : 0.0;
356
- const sun_variant_factor = lerp(1.18, 0.74, mu_k);
357
- const rough_ontogeny_offset = lerp(-0.10 * vein_contrast, 0.07 * vein_contrast, mu_k);
358
-
359
- for (let ly_px = 0; ly_px < res; ly_px++) {
360
- const v = (ly_px + 0.5) / res;
361
- const atlas_y = tile_y0 + ly_px;
362
- const row_offset = atlas_y * atlas_w;
363
- // Prevent top-edge vertical bleeding into adjacent stacked tiles while keeping v=0 stem anchor solid
364
- const top_border_fade = smoothStep(1.0, 0.975, v);
365
-
366
- for (let lx_px = 0; lx_px < res; lx_px++) {
367
- const u = (lx_px + 0.5) / res;
368
- const atlas_x = tile_x0 + lx_px;
369
- const p_idx = row_offset + atlas_x;
370
-
371
- // Central woody twig / rachis along u = anchor_u, v in [anchor_v, anchor_v + 0.72]
372
- let stem_mask = 0.0;
373
- if (v >= anchor_v && v <= anchor_v + 0.72) {
374
- const u_stem = clamp((v - anchor_v) / 0.72, 0.0, 1.0);
375
- const stem_half_w = lerp(min_stem_half_w, 0.007, u_stem);
376
- const d_stem = stem_half_w - Math.abs(u - anchor_u);
377
- stem_mask = smoothStep(-0.008, 0.008, d_stem);
378
- }
379
-
380
- let best_mask = 0.0;
381
- let best_vein = 0.0;
382
- let best_h = 0.0;
383
- let best_tip = 0.0;
384
- let best_edge_norm = 0.5;
385
-
386
- for (let l = 0; l < leaflets.length; l++) {
387
- const lf = leaflets[l];
388
- const dx = u - lf.ox;
389
- const dy = v - lf.oy;
390
- const ly = (dx * lf.dir_x + dy * lf.dir_y) / lf.length;
391
- const lx = (dx * lf.dir_y - dy * lf.dir_x) / lf.width;
392
-
393
- const eval_res = evaluate_leaflet(lx, ly, shape, mu_k, shape_var, vein_contrast);
394
- if (eval_res.mask > best_mask) {
395
- best_mask = eval_res.mask;
396
- best_vein = eval_res.vein;
397
- best_h = eval_res.height;
398
- best_tip = clamp(ly, 0.0, 1.0);
399
- best_edge_norm = eval_res.edge_norm;
400
- }
401
- }
402
-
403
- best_mask *= top_border_fade;
404
- const alpha = clamp(Math.max(best_mask, stem_mask), 0.0, 1.0);
405
- height_field[p_idx] = Math.max(best_h * top_border_fade, stem_mask * 0.4);
406
-
407
- sdnoise3_array(SCRATCH_NOISE, u * 6.0 + ox, v * 6.0 + oy, 0.0);
408
- const n_var = SCRATCH_NOISE[0] * 0.5 + 0.5;
409
-
410
- // 1. Base photosynthetic chlorophyll + carotenoid lamina reflectance (with juvenile chartreuse shift)
411
- const vein_mix_w = lerp(0.38, 0.72, mu_k) * vein_str;
412
- const mix_t = clamp(best_vein * vein_mix_w + best_tip * 0.24 + n_var * 0.18, 0.0, 1.0);
413
- let cr = lerp(p_r, s_r, mix_t);
414
- let cg = lerp(p_g, s_g, mix_t);
415
- let cb = lerp(p_b, s_b, mix_t);
416
-
417
- // Juvenile protochlorophyllide lag: higher mesophyll reflectance + yellow-green chartreuse shift
418
- if (juv_factor > 1e-4) {
419
- const tip_boost = 0.75 + 0.25 * best_tip;
420
- const j_w = juv_factor * tip_boost;
421
- cr = clamp(cr + j_w * 0.22, 0.0, 1.0);
422
- cg = clamp(cg + j_w * 0.28, 0.0, 1.0);
423
- cb = clamp(cb + j_w * 0.04, 0.0, 1.0);
424
- }
425
-
426
- // Transient juvenile epidermal anthocyanin flush along expanding young leaf margins/tips
427
- const w_ant_juv = juv_antho * Math.pow(1.0 - mu_k, 1.8)
428
- * (0.30 + 0.70 * (1.0 - best_edge_norm * 0.65) * (0.35 + 0.65 * best_tip))
429
- * (1.0 - sigma_k);
430
- if (w_ant_juv > 1e-4) {
431
- cr = lerp(cr, 0.58, w_ant_juv * 0.75);
432
- cg = lerp(cg, 0.24, w_ant_juv * 0.65);
433
- cb = lerp(cb, 0.14, w_ant_juv * 0.65);
434
- }
435
-
436
- // 2. First-principles autumn senescence (Chlorophyll catabolism -> Carotenoid unmasking -> Anthocyanin -> Tannin)
437
- if (sigma_k > 1e-4) {
438
- // Vascular bundles (midrib & secondary veins) and basal petiole retain chlorophyll longest
439
- const vascular_shield = clamp(
440
- 0.48 * best_vein + 0.34 * best_edge_norm * (1.0 - 0.55 * best_tip) + 0.18 * n_var,
441
- 0.0,
442
- 1.0
443
- );
444
- const r_chl_lin = clamp(1.0 - sigma_k * (1.36 - 0.68 * vascular_shield), 0.0, 1.0);
445
- const r_chl = r_chl_lin * r_chl_lin;
446
- const chl_loss = 1.0 - r_chl;
447
-
448
- // (a) Unmask plastid carotenoids (xanthophyll / beta-carotene -> golden-yellow)
449
- const car_r = lerp(0.76, 0.94, car_density);
450
- const car_g = lerp(0.54, 0.74, car_density);
451
- const car_b = lerp(0.14, 0.08, car_density);
452
- const w_car = clamp(chl_loss * (0.38 + 0.62 * car_density), 0.0, 1.0);
453
- cr = lerp(cr, car_r, w_car);
454
- cg = lerp(cg, car_g, w_car);
455
- cb = lerp(cb, car_b, w_car);
456
-
457
- // (b) De novo vacuolar anthocyanin synthesis (high light + margin/tip sugar accumulation -> scarlet/crimson)
458
- if (antho_pot > 1e-4) {
459
- const margin_sugar = clamp(
460
- 0.52 * (1.0 - best_edge_norm) + 0.34 * best_tip + 0.22 * (1.0 - best_vein) + 0.15 * (1.0 - n_var),
461
- 0.0,
462
- 1.0
463
- );
464
- const w_ant = clamp(
465
- antho_pot * chl_loss * Math.pow(sigma_k, 0.72) * sun_variant_factor * (0.42 + 0.78 * margin_sugar),
466
- 0.0,
467
- 1.0
468
- );
469
- // Vacuolar anthocyanin strongly absorbs green (~530nm) and blue while transmitting red (~650nm)
470
- cr = lerp(cr, 0.82, w_ant * 0.85);
471
- cg *= lerp(1.0, 0.18, w_ant);
472
- cb *= lerp(1.0, 0.24, w_ant);
473
- }
474
-
475
- // (c) Late-senescence condensed tannin / polyphenol oxidation into russet/copper-brown
476
- if (tannin_ox > 1e-4 && sigma_k > 0.22) {
477
- const w_tan = clamp(
478
- tannin_ox
479
- * chl_loss * chl_loss
480
- * smoothStep(0.22, 0.95, sigma_k)
481
- * lerp(0.68, 1.22, mu_k)
482
- * (0.42 + 0.72 * (1.0 - best_edge_norm * 0.7)),
483
- 0.0,
484
- 1.0
485
- );
486
- cr = lerp(cr, 0.44, w_tan);
487
- cg = lerp(cg, 0.24, w_tan);
488
- cb = lerp(cb, 0.10, w_tan);
489
- }
490
- }
491
-
492
- // 3. Petiole / rachis coloration: herbaceous green on juvenile shoots -> suberized woody brown on mature shoots
493
- if (stem_mask > best_mask) {
494
- const stem_r = lerp(lerp(p_r, 0.32, 0.55), 0.32, mu_k);
495
- const stem_g = lerp(lerp(p_g, 0.38, 0.55), 0.26, mu_k);
496
- const stem_b = lerp(lerp(p_b, 0.16, 0.55), 0.16, mu_k);
497
- cr = lerp(cr, stem_r, stem_mask * 0.75);
498
- cg = lerp(cg, stem_g, stem_mask * 0.75);
499
- cb = lerp(cb, stem_b, stem_mask * 0.75);
500
- }
501
-
502
- // Subtle basal petiole ambient darkening
503
- const base_shade = 0.82 + 0.18 * v;
504
- cr = Math.max(0.01, cr * base_shade);
505
- cg = Math.max(0.01, cg * base_shade);
506
- cb = Math.max(0.005, cb * base_shade);
507
-
508
- const i4 = p_idx * 4;
509
- albedo_data[i4] = clamp(Math.round(cr * 255), 1, 255);
510
- albedo_data[i4 + 1] = clamp(Math.round(cg * 255), 1, 255);
511
- albedo_data[i4 + 2] = clamp(Math.round(cb * 255), 1, 255);
512
- albedo_data[i4 + 3] = clamp(Math.round(alpha * 255), 0, 255);
513
-
514
- const ao = clamp(0.75 + 0.25 * best_h, 0.25, 1.0);
515
- const rough = clamp(
516
- base_rough + rough_ontogeny_offset + sigma_k * 0.08 - best_vein * 0.08 + (1.0 - n_var) * 0.06,
517
- 0.15,
518
- 0.95
519
- );
520
- orm_data[i4] = clamp(Math.round(ao * 255), 0, 255);
521
- orm_data[i4 + 1] = clamp(Math.round(rough * 255), 0, 255);
522
- orm_data[i4 + 2] = 0;
523
- orm_data[i4 + 3] = 255;
524
- }
525
- }
526
-
527
- // Pass 2 (per-tile): Central-difference tangent-space normal map clamped to tile bounds
528
- const tile_vein_scale = lerp(1.0 - 0.58 * vein_contrast, 1.0 + 0.35 * vein_contrast, mu_k);
529
- const norm_str = (1.6 * vein_str + 0.35) * tile_vein_scale;
530
- for (let ly_px = 0; ly_px < res; ly_px++) {
531
- const y0 = tile_y0 + Math.max(0, ly_px - 1);
532
- const y1 = tile_y0 + Math.min(res - 1, ly_px + 1);
533
- const yc = tile_y0 + ly_px;
534
-
535
- for (let lx_px = 0; lx_px < res; lx_px++) {
536
- const x0 = tile_x0 + Math.max(0, lx_px - 1);
537
- const x1 = tile_x0 + Math.min(res - 1, lx_px + 1);
538
- const xc = tile_x0 + lx_px;
539
-
540
- const dh_du = (height_field[yc * atlas_w + x1] - height_field[yc * atlas_w + x0]) * 0.5 * norm_str;
541
- const dh_dv = (height_field[y1 * atlas_w + xc] - height_field[y0 * atlas_w + xc]) * 0.5 * norm_str;
542
-
543
- let nx = -dh_du;
544
- let ny = -dh_dv;
545
- const nz = 1.0;
546
- const nl = Math.sqrt(nx * nx + ny * ny + nz * nz);
547
- nx /= nl;
548
- ny /= nl;
549
-
550
- const i2 = (yc * atlas_w + xc) * 2;
551
- normal_data[i2] = clamp(Math.round((nx * 0.5 + 0.5) * 255), 0, 255);
552
- normal_data[i2 + 1] = clamp(Math.round((ny * 0.5 + 0.5) * 255), 0, 255);
553
- }
554
- }
555
- }
556
-
557
- const albedo_image = ShadeImage.fromSampler2D(albedo_sampler);
558
- albedo_image.color_space = ColorSpace.SRGB;
559
- // CRITICAL: Keep AlphaMode.Straight so texture_write_to_gpu premultiplies once on upload
560
- // and G-buffer albedo_unpremultiply recovers clean dilated leaf color at cutout boundaries.
561
- albedo_image.alpha_mode = AlphaMode.Straight;
562
- const texture_albedo = ShadeTexture.from(albedo_image);
563
- texture_albedo.label = "foliage_leaf_albedo";
564
- texture_albedo.color_space = ColorSpace.SRGB;
565
- texture_albedo.mipmapGenerationFilter = TextureFilterType.MagicKernelSharp;
566
- texture_albedo.wrapS = TextureWrapType.ClampToEdge;
567
- texture_albedo.wrapT = TextureWrapType.ClampToEdge;
568
-
569
- const normal_image = ShadeImage.fromSampler2D(normal_sampler);
570
- normal_image.color_space = ColorSpace.None;
571
- normal_image.alpha_mode = AlphaMode.Opaque;
572
- const texture_normal = ShadeTexture.from(normal_image);
573
- texture_normal.label = "foliage_leaf_normal";
574
- texture_normal.color_space = ColorSpace.LinearSRGB;
575
- texture_normal.mipmapGenerationFilter = TextureFilterType.LinearNormal;
576
- texture_normal.wrapS = TextureWrapType.ClampToEdge;
577
- texture_normal.wrapT = TextureWrapType.ClampToEdge;
578
-
579
- const orm_image = ShadeImage.fromSampler2D(orm_sampler);
580
- orm_image.color_space = ColorSpace.None;
581
- orm_image.alpha_mode = AlphaMode.Opaque;
582
- const texture_orm = ShadeTexture.from(orm_image);
583
- texture_orm.label = "foliage_leaf_orm";
584
- texture_orm.color_space = ColorSpace.LinearSRGB;
585
- texture_orm.wrapS = TextureWrapType.ClampToEdge;
586
- texture_orm.wrapT = TextureWrapType.ClampToEdge;
587
-
588
- const material = new StandardShadeMaterial();
589
- material.name = "foliage_leaf_material";
590
- material.texture_albedo = texture_albedo;
591
- material.texture_normal = texture_normal;
592
- material.texture_orm = texture_orm;
593
- material.roughness_factor = 1.0;
594
- material.metallic_factor = 0.0;
595
- // CRITICAL: Keep transmission_factor = 0 on AlphaTested cards so transparent card corners
596
- // do not act as refractive glass in the path tracer!
597
- material.transmission_factor = 0.0;
598
- material.ambient_factors.a = 1.0;
599
- material.ambient_factors.b = 0.0;
600
- material.transparency_mode = TransparencyMode.AlphaTested;
601
- material.transparency = TransparencyMode.AlphaTested;
602
- material.draw_side = ShadeDrawSide.Double;
603
-
604
- return material;
605
- }
1
+ import { clamp } from "../../../core/math/clamp.js";
2
+ import { lerp } from "../../../core/math/lerp.js";
3
+ import { sdnoise3_array } from "../../../core/math/noise/sdnoise.js";
4
+ import { seededRandom } from "../../../core/math/random/seededRandom.js";
5
+ import { smoothStep } from "../../../core/math/smoothStep.js";
6
+ import { Sampler2D } from "../../../engine/graphics/texture/sampler/Sampler2D.js";
7
+ import { ShadeDrawSide } from "../../../shade/renderer/material/ShadeDrawSide.js";
8
+ import { StandardShadeMaterial } from "../../../shade/renderer/material/StandardShadeMaterial.js";
9
+ import { TransparencyMode } from "../../../shade/renderer/material/TransparencyMode.js";
10
+ import { ColorSpace } from "../../../shade/renderer/texture/ColorSpace.js";
11
+ import { ShadeTexture } from "../../../shade/renderer/texture/ShadeTexture.js";
12
+ import { TextureFilterType } from "../../../shade/renderer/texture/TextureFilterType.js";
13
+ import { TextureWrapType } from "../../../shade/renderer/texture/TextureWrapType.js";
14
+ import { AlphaMode } from "../../../shade/renderer/texture/source/AlphaMode.js";
15
+ import { ShadeImage } from "../../../shade/renderer/texture/source/ShadeImage.js";
16
+ import {
17
+ FOLIAGE_CHLOROPHYLL_LOSS_RATE,
18
+ foliage_variant_senescence
19
+ } from "../skeleton/foliage_senescence.js";
20
+ import { compute_foliage_variant_atlas_layout } from "./compute_foliage_variant_atlas_layout.js";
21
+ import { foliage_atlas_cutout_fit_alpha } from "./foliage_atlas_cutout.js";
22
+ import { foliage_tile_layout, foliage_tile_raster } from "./foliage_tile.js";
23
+
24
+ const SCRATCH_NOISE = new Float32Array(4);
25
+
26
+ /**
27
+ * Synthesizes a turn-key procedural PBR cutout `StandardShadeMaterial` (`TransparencyMode.AlphaTested`,
28
+ * `ShadeDrawSide.Double`) for a species' foliage cards, packing its `foliage_material.variant_count` ontogenetic and
29
+ * biochemically senescent variants into the texture atlas via `MaxRectanglesPacker` (`pack_max_rectangles`), with
30
+ * dilated straight-alpha Albedo (`AlphaMode.Straight`, `ColorSpace.SRGB`), 2-channel Normal map
31
+ * (`ColorSpace.LinearSRGB`), and ORM (`ColorSpace.LinearSRGB`).
32
+ *
33
+ * Every tile draws the species' leaf (or a stretch of its needle shoot) at its true size, from its architecture
34
+ * (`foliage_tile_layout`, `foliage_tile_raster`): the outline's exact coverage, its veins, its petiole.
35
+ *
36
+ * The atlas's shape comes out alongside it in `out_cutout`: per tile, the hull of everything drawn and the leaf
37
+ * coverage, which the card geometry and the card density are built on.
38
+ *
39
+ * @param {import("../config/TreeSpeciesConfig.js").TreeSpeciesConfig} species
40
+ * @param {import("./FoliageAtlasCutout.js").FoliageAtlasCutout|null} [out_cutout]
41
+ * @returns {StandardShadeMaterial}
42
+ */
43
+ export function make_foliage_material(species, out_cutout = null) {
44
+ const cfg = species.foliage_material;
45
+ const tiles = foliage_tile_layout(species);
46
+ const layout = compute_foliage_variant_atlas_layout(tiles.resolution, tiles.variant_count);
47
+ const res = layout.resolution;
48
+ const tile_count = layout.variant_count;
49
+ const atlas_w = layout.atlas_w;
50
+ const atlas_h = layout.atlas_h;
51
+ const boxes = layout.boxes;
52
+
53
+ const rng = seededRandom((species.seed ^ 0x7F4A7C15) | 0);
54
+
55
+ const albedo_sampler = Sampler2D.uint8(4, atlas_w, atlas_h);
56
+ const normal_sampler = Sampler2D.uint8(2, atlas_w, atlas_h);
57
+ const orm_sampler = Sampler2D.uint8(4, atlas_w, atlas_h);
58
+
59
+ const albedo_data = albedo_sampler.data;
60
+ const normal_data = normal_sampler.data;
61
+ const orm_data = orm_sampler.data;
62
+
63
+ const height_field = new Float32Array(atlas_w * atlas_h);
64
+ const base_rough = clamp(cfg.roughness, 0.1, 1.0);
65
+ const vein_str = clamp(cfg.vein_strength, 0.0, 1.0);
66
+
67
+ // Ontogeny & first-principles biochemical senescence parameters
68
+ const juv_shift = clamp(cfg.juvenile_color_shift ?? 0.38, 0.0, 1.0);
69
+ const juv_antho = clamp(cfg.juvenile_anthocyanin ?? 0.08, 0.0, 1.0);
70
+ const vein_contrast = clamp(cfg.ontogeny_vein_contrast ?? 0.55, 0.0, 1.0);
71
+
72
+ // Honour both first-principles `senescence` and legacy `autumn_tint`
73
+ const senescence = clamp(Math.max(cfg.senescence ?? 0.0, cfg.autumn_tint ?? 0.0), 0.0, 1.0);
74
+ const car_density = clamp(cfg.carotenoid_density ?? 0.75, 0.0, 1.0);
75
+ const antho_pot = clamp(cfg.anthocyanin_potential ?? 0.35, 0.0, 1.0);
76
+ const tannin_ox = clamp(cfg.tannin_oxidation ?? 0.25, 0.0, 1.0);
77
+
78
+ const p_r = cfg.primary_color.r;
79
+ const p_g = cfg.primary_color.g;
80
+ const p_b = cfg.primary_color.b;
81
+ const s_r = cfg.secondary_color.r;
82
+ const s_g = cfg.secondary_color.g;
83
+ const s_b = cfg.secondary_color.b;
84
+
85
+ // Pre-fill entire atlas with dilated base RGB (alpha = 0) and neutral normal/ORM so any
86
+ // unused rectangle cells (e.g., when variant_count = 3 or 5) still carry valid dilated RGB.
87
+ const fill_r = clamp(Math.round(Math.max(0.04, p_r) * 255), 1, 255);
88
+ const fill_g = clamp(Math.round(Math.max(0.04, p_g) * 255), 1, 255);
89
+ const fill_b = clamp(Math.round(Math.max(0.02, p_b) * 255), 1, 255);
90
+ const fill_rough = clamp(Math.round(base_rough * 255), 0, 255);
91
+ const total_texels = atlas_w * atlas_h;
92
+ for (let p = 0; p < total_texels; p++) {
93
+ const i4 = p * 4;
94
+ albedo_data[i4] = fill_r;
95
+ albedo_data[i4 + 1] = fill_g;
96
+ albedo_data[i4 + 2] = fill_b;
97
+ albedo_data[i4 + 3] = 0;
98
+
99
+ const i2 = p * 2;
100
+ normal_data[i2] = 128;
101
+ normal_data[i2 + 1] = 128;
102
+
103
+ orm_data[i4] = 255;
104
+ orm_data[i4 + 1] = fill_rough;
105
+ orm_data[i4 + 2] = 0;
106
+ orm_data[i4 + 3] = 255;
107
+ }
108
+
109
+ if (out_cutout !== null) {
110
+ out_cutout.resize(tile_count);
111
+ }
112
+
113
+ for (let v_idx = 0; v_idx < tile_count; v_idx++) {
114
+ const box = boxes[v_idx];
115
+ const tile_x0 = box.x0;
116
+ const tile_y0 = box.y0;
117
+
118
+ // Ontogenetic coordinate mu_k in [0, 1]: 0 = juvenile apical flush, 1 = mature basal foliage
119
+ const raster = foliage_tile_raster(species, tiles, v_idx);
120
+ const mu_k = raster.maturity;
121
+ const ox = (rng() - 0.5) * 150.0 + v_idx * 37.3;
122
+ const oy = (rng() - 0.5) * 150.0 + v_idx * 53.7;
123
+
124
+ // Ontogenetic chlorophyll accumulation (juvenile protochlorophyllide lag -> lighter yellow-green)
125
+ const juv_factor = (1.0 - mu_k) * juv_shift;
126
+ // Staggered variant senescence progression across the atlas so autumn crowns exhibit natural leaf-to-leaf diversity
127
+ const sigma_k = foliage_variant_senescence(senescence, mu_k);
128
+ const sun_variant_factor = lerp(1.18, 0.74, mu_k);
129
+ const rough_ontogeny_offset = lerp(-0.10 * vein_contrast, 0.07 * vein_contrast, mu_k);
130
+
131
+ for (let ly_px = 0; ly_px < res; ly_px++) {
132
+ const v = (ly_px + 0.5) / res;
133
+ const atlas_y = tile_y0 + ly_px;
134
+ const row_offset = atlas_y * atlas_w;
135
+ for (let lx_px = 0; lx_px < res; lx_px++) {
136
+ const u = (lx_px + 0.5) / res;
137
+ const atlas_x = tile_x0 + lx_px;
138
+ const p_idx = row_offset + atlas_x;
139
+ const t_idx = ly_px * res + lx_px;
140
+
141
+ const alpha = raster.alpha[t_idx];
142
+ const best_mask = alpha;
143
+ const best_vein = raster.vein[t_idx];
144
+ const best_tip = raster.tip[t_idx];
145
+ const best_edge_norm = raster.edge_norm[t_idx];
146
+ const best_h = raster.height[t_idx];
147
+ const stem_mask = raster.stem[t_idx];
148
+ height_field[p_idx] = Math.max(best_h, stem_mask * 0.4);
149
+
150
+ const alpha_byte = clamp(Math.round(alpha * 255), 0, 255);
151
+ // a texel the leaf does not cover keeps the dilated fill: nothing is drawn there
152
+ if (alpha_byte === 0) continue;
153
+
154
+ sdnoise3_array(SCRATCH_NOISE, u * 6.0 + ox, v * 6.0 + oy, 0.0);
155
+ const n_var = SCRATCH_NOISE[0] * 0.5 + 0.5;
156
+
157
+ // 1. Base photosynthetic chlorophyll + carotenoid lamina reflectance (with juvenile chartreuse shift)
158
+ const vein_mix_w = lerp(0.38, 0.72, mu_k) * vein_str;
159
+ const mix_t = clamp(best_vein * vein_mix_w + best_tip * 0.24 + n_var * 0.18, 0.0, 1.0);
160
+ let cr = lerp(p_r, s_r, mix_t);
161
+ let cg = lerp(p_g, s_g, mix_t);
162
+ let cb = lerp(p_b, s_b, mix_t);
163
+
164
+ // Juvenile protochlorophyllide lag: higher mesophyll reflectance + yellow-green chartreuse shift
165
+ if (juv_factor > 1e-4) {
166
+ const tip_boost = 0.75 + 0.25 * best_tip;
167
+ const j_w = juv_factor * tip_boost;
168
+ cr = clamp(cr + j_w * 0.22, 0.0, 1.0);
169
+ cg = clamp(cg + j_w * 0.28, 0.0, 1.0);
170
+ cb = clamp(cb + j_w * 0.04, 0.0, 1.0);
171
+ }
172
+
173
+ // Transient juvenile epidermal anthocyanin flush along expanding young leaf margins/tips
174
+ const w_ant_juv = juv_antho * Math.pow(1.0 - mu_k, 1.8)
175
+ * (0.30 + 0.70 * (1.0 - best_edge_norm * 0.65) * (0.35 + 0.65 * best_tip))
176
+ * (1.0 - sigma_k);
177
+ if (w_ant_juv > 1e-4) {
178
+ cr = lerp(cr, 0.58, w_ant_juv * 0.75);
179
+ cg = lerp(cg, 0.24, w_ant_juv * 0.65);
180
+ cb = lerp(cb, 0.14, w_ant_juv * 0.65);
181
+ }
182
+
183
+ // 2. First-principles autumn senescence (Chlorophyll catabolism -> Carotenoid unmasking -> Anthocyanin -> Tannin)
184
+ if (sigma_k > 1e-4) {
185
+ // Vascular bundles (midrib & secondary veins) and basal petiole retain chlorophyll longest
186
+ const vascular_shield = clamp(
187
+ 0.48 * best_vein + 0.34 * best_edge_norm * (1.0 - 0.55 * best_tip) + 0.18 * n_var,
188
+ 0.0,
189
+ 1.0
190
+ );
191
+ const r_chl_lin = clamp(1.0 - sigma_k * (FOLIAGE_CHLOROPHYLL_LOSS_RATE - 0.68 * vascular_shield), 0.0, 1.0);
192
+ const r_chl = r_chl_lin * r_chl_lin;
193
+ const chl_loss = 1.0 - r_chl;
194
+
195
+ // (a) Unmask plastid carotenoids (xanthophyll / beta-carotene -> golden-yellow)
196
+ const car_r = lerp(0.76, 0.94, car_density);
197
+ const car_g = lerp(0.54, 0.74, car_density);
198
+ const car_b = lerp(0.14, 0.08, car_density);
199
+ const w_car = clamp(chl_loss * (0.38 + 0.62 * car_density), 0.0, 1.0);
200
+ cr = lerp(cr, car_r, w_car);
201
+ cg = lerp(cg, car_g, w_car);
202
+ cb = lerp(cb, car_b, w_car);
203
+
204
+ // (b) De novo vacuolar anthocyanin synthesis (high light + margin/tip sugar accumulation -> scarlet/crimson)
205
+ if (antho_pot > 1e-4) {
206
+ const margin_sugar = clamp(
207
+ 0.52 * (1.0 - best_edge_norm) + 0.34 * best_tip + 0.22 * (1.0 - best_vein) + 0.15 * (1.0 - n_var),
208
+ 0.0,
209
+ 1.0
210
+ );
211
+ const w_ant = clamp(
212
+ antho_pot * chl_loss * Math.pow(sigma_k, 0.72) * sun_variant_factor * (0.42 + 0.78 * margin_sugar),
213
+ 0.0,
214
+ 1.0
215
+ );
216
+ // Vacuolar anthocyanin strongly absorbs green (~530nm) and blue while transmitting red (~650nm)
217
+ cr = lerp(cr, 0.82, w_ant * 0.85);
218
+ cg *= lerp(1.0, 0.18, w_ant);
219
+ cb *= lerp(1.0, 0.24, w_ant);
220
+ }
221
+
222
+ // (c) Late-senescence condensed tannin / polyphenol oxidation into russet/copper-brown
223
+ if (tannin_ox > 1e-4 && sigma_k > 0.22) {
224
+ const w_tan = clamp(
225
+ tannin_ox
226
+ * chl_loss * chl_loss
227
+ * smoothStep(0.22, 0.95, sigma_k)
228
+ * lerp(0.68, 1.22, mu_k)
229
+ * (0.42 + 0.72 * (1.0 - best_edge_norm * 0.7)),
230
+ 0.0,
231
+ 1.0
232
+ );
233
+ cr = lerp(cr, 0.44, w_tan);
234
+ cg = lerp(cg, 0.24, w_tan);
235
+ cb = lerp(cb, 0.10, w_tan);
236
+ }
237
+ }
238
+
239
+ // 3. Petiole / rachis coloration: herbaceous green on juvenile shoots -> suberized woody brown on mature shoots
240
+ if (stem_mask > 0) {
241
+ const stem_r = lerp(lerp(p_r, 0.32, 0.55), 0.32, mu_k);
242
+ const stem_g = lerp(lerp(p_g, 0.38, 0.55), 0.26, mu_k);
243
+ const stem_b = lerp(lerp(p_b, 0.16, 0.55), 0.16, mu_k);
244
+ cr = lerp(cr, stem_r, stem_mask * 0.75);
245
+ cg = lerp(cg, stem_g, stem_mask * 0.75);
246
+ cb = lerp(cb, stem_b, stem_mask * 0.75);
247
+ }
248
+
249
+ // Subtle basal petiole ambient darkening
250
+ const base_shade = 0.82 + 0.18 * v;
251
+ cr = Math.max(0.01, cr * base_shade);
252
+ cg = Math.max(0.01, cg * base_shade);
253
+ cb = Math.max(0.005, cb * base_shade);
254
+
255
+ const i4 = p_idx * 4;
256
+ albedo_data[i4] = clamp(Math.round(cr * 255), 1, 255);
257
+ albedo_data[i4 + 1] = clamp(Math.round(cg * 255), 1, 255);
258
+ albedo_data[i4 + 2] = clamp(Math.round(cb * 255), 1, 255);
259
+ albedo_data[i4 + 3] = alpha_byte;
260
+
261
+ const ao = clamp(0.75 + 0.25 * best_h, 0.25, 1.0);
262
+ const rough = clamp(
263
+ base_rough + rough_ontogeny_offset + sigma_k * 0.08 - best_vein * 0.08 + (1.0 - n_var) * 0.06,
264
+ 0.15,
265
+ 0.95
266
+ );
267
+ orm_data[i4] = clamp(Math.round(ao * 255), 0, 255);
268
+ orm_data[i4 + 1] = clamp(Math.round(rough * 255), 0, 255);
269
+ orm_data[i4 + 2] = 0;
270
+ orm_data[i4 + 3] = 255;
271
+ }
272
+ }
273
+
274
+ if (out_cutout !== null) {
275
+ foliage_atlas_cutout_fit_alpha(out_cutout, v_idx, raster.alpha, res);
276
+ }
277
+
278
+ // Pass 2 (per-tile): Central-difference tangent-space normal map clamped to tile bounds
279
+ const tile_vein_scale = lerp(1.0 - 0.58 * vein_contrast, 1.0 + 0.35 * vein_contrast, mu_k);
280
+ const norm_str = (1.6 * vein_str + 0.35) * tile_vein_scale;
281
+ for (let ly_px = 0; ly_px < res; ly_px++) {
282
+ const y0 = tile_y0 + Math.max(0, ly_px - 1);
283
+ const y1 = tile_y0 + Math.min(res - 1, ly_px + 1);
284
+ const yc = tile_y0 + ly_px;
285
+
286
+ for (let lx_px = 0; lx_px < res; lx_px++) {
287
+ const x0 = tile_x0 + Math.max(0, lx_px - 1);
288
+ const x1 = tile_x0 + Math.min(res - 1, lx_px + 1);
289
+ const xc = tile_x0 + lx_px;
290
+
291
+ const dh_du = (height_field[yc * atlas_w + x1] - height_field[yc * atlas_w + x0]) * 0.5 * norm_str;
292
+ const dh_dv = (height_field[y1 * atlas_w + xc] - height_field[y0 * atlas_w + xc]) * 0.5 * norm_str;
293
+
294
+ let nx = -dh_du;
295
+ let ny = -dh_dv;
296
+ const nz = 1.0;
297
+ const nl = Math.sqrt(nx * nx + ny * ny + nz * nz);
298
+ nx /= nl;
299
+ ny /= nl;
300
+
301
+ const i2 = (yc * atlas_w + xc) * 2;
302
+ normal_data[i2] = clamp(Math.round((nx * 0.5 + 0.5) * 255), 0, 255);
303
+ normal_data[i2 + 1] = clamp(Math.round((ny * 0.5 + 0.5) * 255), 0, 255);
304
+ }
305
+ }
306
+ }
307
+
308
+ const albedo_image = ShadeImage.fromSampler2D(albedo_sampler);
309
+ albedo_image.color_space = ColorSpace.SRGB;
310
+ // CRITICAL: Keep AlphaMode.Straight so texture_write_to_gpu premultiplies once on upload
311
+ // and G-buffer albedo_unpremultiply recovers clean dilated leaf color at cutout boundaries.
312
+ albedo_image.alpha_mode = AlphaMode.Straight;
313
+ const texture_albedo = ShadeTexture.from(albedo_image);
314
+ texture_albedo.label = "foliage_leaf_albedo";
315
+ texture_albedo.color_space = ColorSpace.SRGB;
316
+ texture_albedo.mipmapGenerationFilter = TextureFilterType.MagicKernelSharp;
317
+ texture_albedo.wrapS = TextureWrapType.ClampToEdge;
318
+ texture_albedo.wrapT = TextureWrapType.ClampToEdge;
319
+
320
+ const normal_image = ShadeImage.fromSampler2D(normal_sampler);
321
+ normal_image.color_space = ColorSpace.None;
322
+ normal_image.alpha_mode = AlphaMode.Opaque;
323
+ const texture_normal = ShadeTexture.from(normal_image);
324
+ texture_normal.label = "foliage_leaf_normal";
325
+ texture_normal.color_space = ColorSpace.LinearSRGB;
326
+ texture_normal.mipmapGenerationFilter = TextureFilterType.LinearNormal;
327
+ texture_normal.wrapS = TextureWrapType.ClampToEdge;
328
+ texture_normal.wrapT = TextureWrapType.ClampToEdge;
329
+
330
+ const orm_image = ShadeImage.fromSampler2D(orm_sampler);
331
+ orm_image.color_space = ColorSpace.None;
332
+ orm_image.alpha_mode = AlphaMode.Opaque;
333
+ const texture_orm = ShadeTexture.from(orm_image);
334
+ texture_orm.label = "foliage_leaf_orm";
335
+ texture_orm.color_space = ColorSpace.LinearSRGB;
336
+ texture_orm.wrapS = TextureWrapType.ClampToEdge;
337
+ texture_orm.wrapT = TextureWrapType.ClampToEdge;
338
+
339
+ const material = new StandardShadeMaterial();
340
+ material.name = "foliage_leaf_material";
341
+ material.texture_albedo = texture_albedo;
342
+ material.texture_normal = texture_normal;
343
+ material.texture_orm = texture_orm;
344
+ material.roughness_factor = 1.0;
345
+ material.metallic_factor = 0.0;
346
+ // CRITICAL: Keep transmission_factor = 0 on AlphaTested cards so transparent card corners
347
+ // do not act as refractive glass in the path tracer!
348
+ material.transmission_factor = 0.0;
349
+ material.ambient_factors.a = 1.0;
350
+ material.ambient_factors.b = 0.0;
351
+ material.transparency_mode = TransparencyMode.AlphaTested;
352
+ material.transparency = TransparencyMode.AlphaTested;
353
+ material.draw_side = ShadeDrawSide.Double;
354
+
355
+ return material;
356
+ }