@woosh/meep-engine 3.56.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.
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
- package/src/core/binary/BitSet.js +1 -1
- package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
- package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
- package/src/core/binary/FLOAT16_MAX.js +1 -0
- package/src/core/binary/base58/base58_encode.js +2 -2
- package/src/core/binary/type/TypeBuilder.js +1 -1
- package/src/core/bvh2/bvh3/BVH.js +1 -1
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
- package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
- package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
- package/src/core/collection/CuckooFilter.js +1 -1
- package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
- package/src/core/collection/array/isArrayEqual.js +33 -58
- package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
- package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
- package/src/core/collection/array/typed/float32_array_hash.js +38 -38
- package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
- package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
- package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
- package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
- package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
- package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
- package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
- package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
- package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
- package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
- package/src/core/collection/list/List.d.ts.map +1 -1
- package/src/core/collection/list/List.js +3 -19
- package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
- package/src/core/collection/table/RowFirstTable.js +4 -28
- package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
- package/src/core/debug/matchers/DescribeAs.js +62 -64
- package/src/core/function/FunctionCompiler.js +4 -4
- package/src/core/function/objectsEqual.d.ts.map +1 -1
- package/src/core/function/objectsEqual.js +3 -2
- package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
- package/src/core/geom/2d/bvh/BVH2D.js +4 -3
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
- package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
- package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
- package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
- package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
- package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
- package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
- package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
- package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_build_frustum.js +20 -53
- package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
- package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
- package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
- package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
- package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
- package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
- package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
- package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
- package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
- package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
- package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
- package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
- package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
- package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
- package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
- package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
- package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
- package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
- package/src/core/geom/3d/shape/MeshShape3D.js +2 -56
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
- package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
- package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
- package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
- package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
- package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
- package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +151 -194
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +8 -14
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +36 -82
- package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
- package/src/core/geom/ConicRay.d.ts.map +1 -1
- package/src/core/geom/ConicRay.js +230 -237
- package/src/core/localization/LocaleDataset.d.ts +6 -0
- package/src/core/localization/LocaleDataset.d.ts.map +1 -1
- package/src/core/localization/LocaleDataset.js +48 -37
- package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
- package/src/core/localization/LocalizationEngine.js +3 -2
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +3 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
- package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
- package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
- package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
- package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
- package/src/core/model/DebouncedObservedBoolean.js +1 -1
- package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
- package/src/core/model/node-graph/node/NodeInstance.js +2 -7
- package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
- package/src/core/model/object/optional_equality.d.ts +3 -3
- package/src/core/model/object/optional_equality.d.ts.map +1 -1
- package/src/core/model/object/optional_equality.js +10 -27
- package/src/core/model/object/write_property.js +1 -1
- package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
- package/src/core/primitives/strings/string_compute_byte_size.d.ts +3 -3
- package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +1 -1
- package/src/core/primitives/strings/string_compute_byte_size.js +8 -21
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +14 -2
- package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
- package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
- package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
- package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
- package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
- package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +4 -1
- package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
- package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
- package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
- package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
- package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem.js +2 -1
- package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
- package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
- package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
- package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
- package/src/engine/input/ecs/systems/InputSystem.js +2 -1
- package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
- package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
- package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
- package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
- package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
- package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
- package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
- package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
- package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
- package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
- package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
- package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
- package/src/engine/intelligence/mcts/StateNode.js +366 -364
- package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
- package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
- package/src/engine/navigation/ecs/components/Path.js +2 -1
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
- package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
- package/src/engine/physics/body/SolverBodyState.js +2 -6
- package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
- package/src/engine/physics/ccd/linear_sweep.js +3 -16
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
- package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
- package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
- package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
- package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_velocity.js +3 -18
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
- package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
- package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
- package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
- package/src/engine/save/StorageBackedList.d.ts +5 -0
- package/src/engine/save/StorageBackedList.d.ts.map +1 -1
- package/src/engine/save/StorageBackedList.js +161 -144
- package/src/engine/simulation/Ticker.d.ts.map +1 -1
- package/src/engine/simulation/Ticker.js +394 -391
- package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
- package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
- package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
- package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
- package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
- package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
- package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
- package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
- package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
- package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
- package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
- package/src/format/image/avif/av1/encode/quantise.js +1 -55
- package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
- package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
- package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
- package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
- package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
- package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
- package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
- package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
- package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
- package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
- package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
- package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
- package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
- package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
- package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
- package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
- package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
- package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
- package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
- package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
- package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
- package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
- package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
- package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
- package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
- package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
- package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
- package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
- package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
- package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
- package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
- package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
- package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
- package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
- package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
- package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
- package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
- package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
- package/src/generation/foliage/asset/TreeAsset.js +6 -0
- package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
- package/src/generation/foliage/asset/generate_tree.js +23 -6
- package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
- package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
- package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
- package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
- package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
- package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
- package/src/generation/foliage/config/FoliageCardType.js +2 -2
- package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
- package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/FoliageConfig.js +47 -93
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
- package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
- package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
- package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
- package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageTileContent.js +12 -0
- package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
- package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
- package/src/generation/foliage/config/LeafApexShape.js +17 -0
- package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
- package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
- package/src/generation/foliage/config/LeafArchitecture.js +288 -0
- package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
- package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
- package/src/generation/foliage/config/LeafBaseShape.js +21 -0
- package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
- package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
- package/src/generation/foliage/config/LeafLobation.js +14 -0
- package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
- package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
- package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
- package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
- package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
- package/src/generation/foliage/config/ShootBudZone.js +219 -0
- package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
- package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
- package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
- package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
- package/src/generation/foliage/config/ShootSystemRule.js +316 -0
- package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
- package/src/generation/foliage/config/TreeLODConfig.js +1 -1
- package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
- package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
- package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
- package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/TreeWindConfig.js +34 -25
- package/src/generation/foliage/index.d.ts +19 -2
- package/src/generation/foliage/index.js +63 -44
- package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
- package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
- package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
- package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
- package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
- package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
- package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
- package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
- package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
- package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
- package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
- package/src/generation/foliage/material/foliage_tile.js +286 -0
- package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
- package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
- package/src/generation/foliage/material/leaf_geometry.js +528 -0
- package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
- package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_foliage_material.js +356 -605
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
- package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
- package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
- package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
- package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
- package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
- package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
- package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
- package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
- package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
- package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
- package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
- package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
- package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
- package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
- package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
- package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
- package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
- package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
- package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
- package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
- package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
- package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
- package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
- package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
- package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
- package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
- package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
- package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
- package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
- package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
- package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
- package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
- package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
- package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
- package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
- package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
- package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
- package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
- package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
- package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
- package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
- package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
- package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
- package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
- package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
- package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
- package/src/shade/playground/foliage_wind/index.html +6 -0
- package/src/shade/playground/foliage_wind/main.js +14 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
- package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
- package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
- package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
- package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
- package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
- package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
- package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
- package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
- package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
- package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
- package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
- package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
- package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
- package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
- package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
- package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
- package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
- package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
- package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
- package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
- package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
- package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
- package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
- package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
- package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
- package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
- package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
- package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
- package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
- package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
- package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
- package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
- package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
- package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
- package/src/shade/renderer/loader/usd/load_usd.js +6 -19
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
- package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
- package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
- package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
- package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
- package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
- package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
- package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
- package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
- package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
- package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
- package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
- package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
- package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
- package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
- package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
- package/src/shade/renderer/water/shader_water_avboit.js +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
- package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
- package/src/shade/wgsl/validate_wgsl_source.js +27 -1
- package/src/view/controller/controls/ListController.d.ts.map +1 -1
- package/src/view/controller/controls/ListController.js +118 -113
- package/src/view/controller/controls/Vector1Control.js +97 -97
- package/src/view/elements/image/SvgImageView.d.ts +1 -0
- package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
- package/src/view/elements/image/SvgImageView.js +92 -90
- package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
- package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
- package/src/view/tooltip/gml/TooltipParser.js +2 -2
- package/src/engine/network/PriorityFetch.d.ts +0 -59
- package/src/engine/network/PriorityFetch.d.ts.map +0 -1
- package/src/engine/network/PriorityFetch.js +0 -193
- package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Crown Filling by Light
|
|
2
|
+
|
|
3
|
+
Follows `SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md`, which grew every woody species' twigs from sourced shoot
|
|
4
|
+
demography and left the crowns barren.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
Each carrier grows its twig system alone for a fixed number of years, at a fixed vigour (net shoots a shoot leaves a
|
|
9
|
+
year), with shoots shed by a chosen rank of age, order and length. Nothing in that knows where the crown is empty or
|
|
10
|
+
crowded. Seed 1337, against master's metre-long cards:
|
|
11
|
+
|
|
12
|
+
| preset | leaf area, master -> now | side opacity, master -> now |
|
|
13
|
+
| :--- | ---: | ---: |
|
|
14
|
+
| birch | 45 -> 2 m^2 | 0.44 -> 0.10 |
|
|
15
|
+
| willow | 241 -> 7 m^2 | 0.67 -> 0.18 |
|
|
16
|
+
| pine | 174 -> 24 m^2 | 0.69 -> 0.33 |
|
|
17
|
+
| spruce | 161 -> 20 m^2 | 0.57 -> 0.34 |
|
|
18
|
+
| maple | 150 -> 63 m^2 | 0.66 -> 0.43 |
|
|
19
|
+
| oak | 164 -> 113 m^2 | 0.64 -> 0.51 |
|
|
20
|
+
|
|
21
|
+
**The target** is the US Forest Inventory's crown ratings of 15,011 leaf-on trees seen from the side (Randolph 2006,
|
|
22
|
+
USDA GTR SRS-94, Tables 1-4). Healthy crowns block a mean 45% of their outline (oaks, maples, birches 46-51%), and their
|
|
23
|
+
foliated parts let about 15% of skylight through (interquartile 10-20%). From below, open-grown crowns intercept 0.75-0.92
|
|
24
|
+
of light (Nowak 1996, Forest Science 42: 504-507, Table 2).
|
|
25
|
+
|
|
26
|
+
## Principle
|
|
27
|
+
|
|
28
|
+
A real crown is full because it grows until it shades itself. Shoots in light make more shoots; shoots in shade make
|
|
29
|
+
fewer, and an axis in deep shade dies. The papers already in hand measure exactly this:
|
|
30
|
+
|
|
31
|
+
- **Spruce.** Rb, the net shoots a shoot leaves a year, rises with the light a branch receives: about 0.65 at
|
|
32
|
+
4-5 mol m^-2 d^-1 to about 2.2 at 10-12, against 37.1 under open sky, so 0.12 to 0.30 of full light. Below 1 in deep
|
|
33
|
+
shade, a branch's foliage shrinks with age (Niinemets & Lukjanova 2003, New Phytol. 158: 75-89, Fig. 5b, Table 1).
|
|
34
|
+
- **Pine.** Branching stops at a relative light of 0.20-0.25 (Ilonen et al. 1979, Silva Fennica 13: 319-321). A shoot
|
|
35
|
+
with no needles left is dead (Kellomäki & Kurttio 1991, p. 104).
|
|
36
|
+
- **Birch.** The bud population grows 1.52 a year in the top of the crown, 0.999 at its bottom (Maillette 1982, J.
|
|
37
|
+
Appl. Ecol. 19: 219-238, Table 1).
|
|
38
|
+
- **Red maple.** Shaded branches die, so foliage stays at the crown's periphery (Wilson 1966, Harvard Forest Paper 14,
|
|
39
|
+
p. 19).
|
|
40
|
+
|
|
41
|
+
So vigour becomes a function of light, and the crown's leaf area becomes an outcome: growth stops where the crown has
|
|
42
|
+
shaded its own interior to the light at which shoots no longer replace themselves.
|
|
43
|
+
|
|
44
|
+
## Design
|
|
45
|
+
|
|
46
|
+
The framework (trunk, boughs and branches from the generator graph) stays as it is. Everything younger grows by light.
|
|
47
|
+
`tree_skeleton_grow_shoots` is rebuilt around one tree-wide simulation:
|
|
48
|
+
|
|
49
|
+
1. **One season loop for the whole tree.** Every carrier's twig system grows in the same loop, so the systems compete
|
|
50
|
+
for the same light. `years` and the light response move from the per-carrier `ShootSystemRule` to a species-level
|
|
51
|
+
`ShootGrowthConfig`. The rules keep what differs by carrier: bud zones, lengths, orders, angles.
|
|
52
|
+
2. **Shoots have geometry as they grow.** Each new unit's start, heading and end are fixed in its season (tropisms,
|
|
53
|
+
zigzag, insertion and phyllotaxis, as the writer does today), so light can be measured where the leaves are. The
|
|
54
|
+
writer then only turns the surviving axes into skeleton branches.
|
|
55
|
+
3. **The light field.** Each season, the leaf area of every leaf-bearing unit is deposited in a voxel grid over the
|
|
56
|
+
crown.
|
|
57
|
+
- **Light at each voxel:** relative irradiance from the sky by Beer-Lambert, `exp(-G Omega LAD path)`.
|
|
58
|
+
- **Extinction:** `G = 0.5`, the projection of a spherical leaf angle distribution.
|
|
59
|
+
- **Clumping:** `Omega` is the species' shoot clumping; Scots pine about 0.58 from its silhouette-to-area ratio of
|
|
60
|
+
0.146 (Smolander, Stenberg & Linder 1994, Tree Physiol. 14: 971-980), broadleaves 1 for want of data.
|
|
61
|
+
- **Sky:** a standard overcast sky, radiance `(1 + 2 sin elevation) / 3` (Moon & Spencer 1942), weighted for a
|
|
62
|
+
horizontal receiver as hemispherical photographs measure it.
|
|
63
|
+
- **Directions:** lattice directions, so each is one sweep of the grid. The cost is grid cells times directions,
|
|
64
|
+
whatever the leaf count.
|
|
65
|
+
4. **Vigour follows light.** An axis in relative light `Q` leaves `Rb(Q)` net shoots a year. `Rb` rises linearly from 1
|
|
66
|
+
at the species' compensation light to its full vigour at its saturation light, flat above, and falls below 1 under
|
|
67
|
+
compensation. A season's new shoots on an axis survive at `Rb(Q) / yield`, its gross yield of new shoots. The shoots
|
|
68
|
+
kept are the best lit, with a dithered count so the total is exact on average. This replaces the chosen
|
|
69
|
+
age/order/length rank.
|
|
70
|
+
5. **Death by shade is not a separate rule.** A terminal that is shed takes its axis with it [BB1998], and in shade the
|
|
71
|
+
terminal is shed. A shaded branch thins and dies as `Rb < 1` makes it.
|
|
72
|
+
6. **Long enough to fill.** `years` covers the time the periphery takes to reach the light limit, so crown fullness is
|
|
73
|
+
set by light, not by when the simulation stops. The equilibrium is measured, not assumed.
|
|
74
|
+
7. **Wood.** The [BB2000] Table 7 diameter holds only for current and year-old units, the shoots it was measured on.
|
|
75
|
+
Older wood is the pipe model plus what its laterals need where they join, for twig and carrier alike.
|
|
76
|
+
8. **Framework avoidance** is tested when a unit grows, as now.
|
|
77
|
+
|
|
78
|
+
**Per-species light response:**
|
|
79
|
+
|
|
80
|
+
| preset | compensation `Q` | saturation `Q` | full vigour | source |
|
|
81
|
+
| :--- | ---: | ---: | ---: | :--- |
|
|
82
|
+
| spruce | 0.16 | 0.30 | 2.19 | [NL2003] Fig. 5b line through (0.12, 0.65), (0.30, 2.2); Table 1 max |
|
|
83
|
+
| pine | 0.22 | 0.30 | 1.867 | Ilonen 1979 (0.20-0.25); saturation spruce's; [NL2003] Fig. 2 |
|
|
84
|
+
| birch | 0.22 | 0.30 | 1.52 | top of crown [M1982]; light points pine's |
|
|
85
|
+
| oak, maple, willow, shrub | chosen | chosen | chosen | none found |
|
|
86
|
+
|
|
87
|
+
**Gaps.** Only spruce has a measured light curve. Pine has its compensation point. The others borrow the curve's
|
|
88
|
+
shape, and that is marked in the code.
|
|
89
|
+
|
|
90
|
+
## Measuring
|
|
91
|
+
|
|
92
|
+
- **Fullness:** crown density and foliage transparency against Randolph 2006, and interception from below against Nowak
|
|
93
|
+
1996, measured with the crown opacity benchmark being built in a sibling session. Until that lands, the scratchpad
|
|
94
|
+
probe stands in.
|
|
95
|
+
- **Specs, from the principle:**
|
|
96
|
+
- In a uniform light field, the twig population changes by `Rb(Q)` a year.
|
|
97
|
+
- Shoots in shade die.
|
|
98
|
+
- Leaf area stops growing with `years` once the crown is full.
|
|
99
|
+
- Doubling `years` past equilibrium changes leaf area little.
|
|
100
|
+
- A crown with more framework does not end up with proportionally more leaf.
|
|
101
|
+
|
|
102
|
+
## Plan
|
|
103
|
+
|
|
104
|
+
1. `ShootGrowthConfig`; the rule loses `years` and `vigour`.
|
|
105
|
+
2. `shoot_light_field`: voxel leaf area, sky sweeps, irradiance query. Specs against Beer-Lambert in closed form.
|
|
106
|
+
3. The tree-wide simulation with geometry, light-driven survival, framework avoidance at growth.
|
|
107
|
+
4. The writer and radii on the simulated axes.
|
|
108
|
+
5. Presets: light response per species.
|
|
109
|
+
6. Specs green (including the willow seam and the season order), mutation-tested.
|
|
110
|
+
7. Measure every preset against the targets; look at each in the playground.
|
|
111
|
+
|
|
112
|
+
## Landed (2026-10-26, uncommitted)
|
|
113
|
+
|
|
114
|
+
As designed, plus what building it turned up:
|
|
115
|
+
|
|
116
|
+
- **The simulation:** `shoot_systems_simulate` runs every carrier's twig system in one season loop against a
|
|
117
|
+
`ShootLightField` (leaf-area voxels of `light_cell`, 17 lattice sweeps of the overcast sky, matches Beer-Lambert in
|
|
118
|
+
closed form within 0.01). Each season: extension with tropisms, short-shoot survival `short_shoot_survival x
|
|
119
|
+
min(1, Rb(Q))`, bursts, syllepsis, shedding to `Rb(Q) / yield` (rank: log keep share, age, order, length, jitter),
|
|
120
|
+
the cascade of a shed mother, then the wood.
|
|
121
|
+
- **Dynamic girth** (Alex's pick over a forecast radius): `ShootGirth` thickens the wood each season with what it
|
|
122
|
+
carries, never thinning: the pipe model at the species' `pipe_model_exponent` over the shoots' Table 7 radius, Table
|
|
123
|
+
7 for a unit of its age, and `1 / SHOOT_LATERAL_RADIUS_RATIO` of a lateral where it joins, on twigs, carriers and the
|
|
124
|
+
framework above them. A shoot grows only where it clears today's wood; a shoot the wood has grown into by the end
|
|
125
|
+
of a season dies with all it carries. The framework hash (`ShootFrameworkHash`, allocation-free) is rebuilt each
|
|
126
|
+
season.
|
|
127
|
+
- **Framework ages** come from the leader growth: a branch is born when its parent's tip passed its seat, so a carrier
|
|
128
|
+
carries `round(age)` units over its whole length.
|
|
129
|
+
- **Cards follow leaves:** a unit carries its leaves (`leaves_per_unit + leaves_per_metre L`, times `leaf_survival` at
|
|
130
|
+
its age) over the leaves one card draws (`foliage_card_leaf_count`), dithered; short shoots get their own rosette
|
|
131
|
+
tiles (`foliage_atlas_tiles.js`).
|
|
132
|
+
- **Skinning seats** (found by the willow seam spec once twigs grew on twigs): where more than four joints meet, the
|
|
133
|
+
four kept are those that leave the seat least far from where all of them would carry it, and a dropped joint folds
|
|
134
|
+
into the kept one that carries the point most alike. "How far apart" is each joint on the path between them turning
|
|
135
|
+
by its reference-wind rotation about its pivot (`TreeSkeleton.joint_rotation`, written by
|
|
136
|
+
`tree_skeleton_assign_skin_joints`). Willow seats over the 1 cm tolerance: 178 by weight-then-hops, 6 by
|
|
137
|
+
weight-times-hops, 0 now.
|
|
138
|
+
|
|
139
|
+
**Specs restated from their principle** (each mutation-tested red):
|
|
140
|
+
- interpenetration: a child may meet its mother's wood only in the crotch, the run of its first segments that still
|
|
141
|
+
lie in her wood, and a child whose tip is in her wood is buried; twigs no longer get a year-old-girth allowance. The
|
|
142
|
+
spec finds candidate pairs by a grid (it was n^2 and timed out at 90k segments).
|
|
143
|
+
- conifer tiers: they come from the whorls (spiral boughs: empty bands 5.4x fewer on spruce, 3.9x on pine);
|
|
144
|
+
plagiotropism no longer moves them (0.95x).
|
|
145
|
+
- spire: the leader's top unit, clothed in at least half the needles a unit of `leader_growth` carries.
|
|
146
|
+
- autumn order: the leaves that fell were more exposed and younger than those kept, by a quarter of the summer spread.
|
|
147
|
+
- shoot demography: from `tree_skeleton_grow`'s records (zones, the four-bud whorl, ancestry, light response).
|
|
148
|
+
|
|
149
|
+
**Measured at seed 1337** with master's `foliage_measure_leaf_area` and `tree_crown_opacity` (copied in for the run):
|
|
150
|
+
|
|
151
|
+
| preset | leaf m^2 | crown LAI | side density | side transparency | below density | below transparency | generate |
|
|
152
|
+
| :--- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
153
|
+
| oak | 90.9 | 3.11 | 0.51 | 0.44 | 0.53 | 0.38 | 0.9 s |
|
|
154
|
+
| pine | 35.0 | 1.60 | 0.38 | 0.60 | 0.41 | 0.53 | 1.0 s |
|
|
155
|
+
| birch | 64.5 | 6.59 | 0.56 | 0.38 | 0.80 | 0.15 | 2.5 s |
|
|
156
|
+
| willow | 136.3 | 3.68 | 0.69 | 0.30 | 0.71 | 0.25 | 2.0 s |
|
|
157
|
+
| maple | 36.3 | 1.42 | 0.33 | 0.55 | 0.32 | 0.43 | 1.1 s |
|
|
158
|
+
| spruce | 117.8 | 4.44 | 0.36 | 0.28 | 0.45 | 0.25 | 3.1 s |
|
|
159
|
+
| shrub | 57.8 | 4.65 | 0.62 | 0.34 | 0.77 | 0.18 | 0.3 s |
|
|
160
|
+
|
|
161
|
+
(generate: skeleton and cards, `probe_crowns.mjs`.) FIA's targets are density 45-51% and transparency about 15%
|
|
162
|
+
[Randolph 2006].
|
|
163
|
+
|
|
164
|
+
**Open, measured:**
|
|
165
|
+
- Every preset is far more see-through than FIA's 15%; only oak's density is in range.
|
|
166
|
+
- **The shrub was barren** at a chosen Rb of 1.3 (2.1 m^2, crown LAI 0.18): light did not limit it, the stool's young
|
|
167
|
+
stems seeded few lineages, and 1.3 of a gross yield of 7.17 kept under one burst shoot in five even in full sun. No
|
|
168
|
+
net shoot yield was found for hazel (Grisafi et al. 2024 report one season's bud fates; orchard LAI 0.80-2.86,
|
|
169
|
+
Oeztuerk et al. 2018, is per ground area). Alex's pick: full-sun vigour is the gross yield the rule's Grisafi
|
|
170
|
+
numbers give (`shoot_expected_yield`, 7.17), so only shade sheds hazel shoots. Light saturates the crown from about
|
|
171
|
+
2.8 up. The shrub row above is measured at that vigour; master's leaf-area and opacity specs pass on this tree.
|
|
172
|
+
- Engulfment took birch from 115 to 83 m^2 (probe), willow from 167 to 157, spruce from 140 to 121.
|
|
@@ -7,7 +7,7 @@ This document specifies a production-grade, State-of-the-Art (SotA) procedural t
|
|
|
7
7
|
### Core Design Tenets
|
|
8
8
|
1. **Turn-Key Top Layer, Layered Override API Underneath**:
|
|
9
9
|
- **Top Layer (1-line turn-key)**: `generate_tree({ preset: TreePreset.Oak, seed: 42 })` or `place_tree(scene_context, dataset, { preset: "pine", position: [10, 0, -5] })` produces a complete, multi-LOD, wind-rigged, PBR-materialized tree asset (`TreeAsset` / `SceneBundle` / `Prefab`) with zero external asset files required.
|
|
10
|
-
- **Mid Layer (Species & Generator Descriptors)**: Declarative `TreeSpeciesConfig`, `
|
|
10
|
+
- **Mid Layer (Species & Generator Descriptors)**: Declarative `TreeSpeciesConfig`, a branch generator graph (`BranchGeneratorConfig` nodes joined by `BranchSpawnRule` edges, foliage placed by `FoliageSpawnRule`s), `CrownConfig`, `FoliageConfig`, `BarkMaterialConfig`, `FoliageMaterialConfig`, and `TreeWindConfig` with `AnimationCurve` profiles and full JSON serialization.
|
|
11
11
|
- **Low Layer (Pure Pipeline Passes)**: Composable, allocation-conscious pure functions operating on `Graph` skeletons, `Transform64` node frames, Hermite spine buffers, `PointHashGrid3` crown fields, and `Geometry` / `Attribute` buffers.
|
|
12
12
|
2. **Zero Duplicate Adjacent Infrastructure**:
|
|
13
13
|
- **Coordinate System**: Strictly Meep's right-handed **Y-up** convention (`Vector3.up = (0, 1, 0)`, ground plane `X-Z`).
|
|
@@ -106,23 +106,58 @@ Evaluating any point or derivative at local parameter $u \in [0, 1]$ along edge
|
|
|
106
106
|
- `spline3_hermite_derivative(u, p0x, p1x, m0x, m1x)` (for $x, y, z$)
|
|
107
107
|
|
|
108
108
|
### 4.2 Hybrid Parametric + Space-Colonization Growth Algorithm
|
|
109
|
-
|
|
109
|
+
Branches are grown breadth-first from the trunk (`species.branches[0]`). Every `species.branch_rules` edge
|
|
110
|
+
`source -> target` (always `source < target`, so the graph is acyclic) spawns branches of generator `target` along
|
|
111
|
+
each branch of generator `source`; one generator may spawn several kinds of children (boughs, roots, stubs, sprouts,
|
|
112
|
+
inter-whorl branches) and several generators may spawn the same kind (fan-in). Branching depth $l$ counts lateral
|
|
113
|
+
hops from the trunk; split forks keep their parent's depth and generator.
|
|
110
114
|
1. **Crown Envelope & Space Colonization Field**:
|
|
111
115
|
- The crown volume is defined by a configurable `CrownEnvelopeType` (`Conical`, `Spherical`, `Hemispherical`, `Cylindrical`, `TaperedCylindrical`, `Flame`, `InverseConical`, `TendFlame`, `Weeping`, or custom `AnimationCurve` profile) centered at $(0, H_{\text{crown}}, 0)$.
|
|
112
116
|
- When `space_colonization_weight > 0`, $N_{\text{attract}}$ attraction points are sampled deterministically inside the crown envelope using `seededRandom` and indexed in a `PointHashGrid3` with cell size equal to the attraction radius $d_i$.
|
|
113
117
|
2. **Branch Spawn & Phyllotactic Budding**:
|
|
114
|
-
- Along each parent branch
|
|
115
|
-
- Child branch length $L_l(t_p)$ is modulated by the
|
|
118
|
+
- Along each parent branch, each outgoing rule spawns its children inside `[attach_min, attach_max]` according to the rule's `PhyllotaxisMode` (`SpiralGolden` $137.507764^\circ$, `AlternateDistichous` $180^\circ$, `OppositeDecussate` $180^\circ + 90^\circ$ flip, `Opposite` $180^\circ$, `Whorled` $360^\circ / M$, `FlareLobes` on the crests of the parent's basal buttress lobes).
|
|
119
|
+
- Child branch length $L_l(t_p)$ is modulated by the rule's `length_profile: AnimationCurve` and, for rules with `crown_envelope`, the crown envelope $S_{\text{env}}(h_{\text{norm}})$. Children of a rule without `crown_envelope` (roots, trunk sprouts) are neither shrunk by the envelope nor kept inside it.
|
|
120
|
+
- Self-pruning: below a crown rule's `attach_min` the rule once grew children too, at the same nodes continued down the stem; they died in the crown's shade. Each keeps `(1 - self_pruning) - age` of its length as a dead stub (age 0 just below the living children, 1 at the stem base; size at death `(1 - age)` of today's), and once that no longer clears the bark it is grown over and becomes a bark scar (knot).
|
|
121
|
+
- Generators with `root` grow structural surface roots: they descend onto the ground plane $y = 0$ and creep along it, add no pipe-model area to their stem, and never receive a wind joint.
|
|
116
122
|
- Initial child heading $\mathbf{T}_c(0)$ diverges from parent tangent $\mathbf{T}_p(t_p)$ by insertion angle $\alpha_{\text{insert}}(t_p)$ around the azimuth $\phi_k$ in the parent's RMF plane $(\mathbf{R}_p, \mathbf{S}_p)$.
|
|
117
123
|
- The child's initial RMF normal $\mathbf{R}_c(0)$ is aligned with the adaxial (upper crotch) projection of $\mathbf{T}_p$:
|
|
118
124
|
$$\mathbf{R}_c(0) = \text{normalize}\big(\mathbf{T}_p - (\mathbf{T}_p \cdot \mathbf{T}_c(0))\mathbf{T}_c(0)\big)$$
|
|
119
125
|
guaranteeing that $\theta = 0$ on the child's cross-section always lies at the top of the branch collar.
|
|
126
|
+
- **Dorsiventral parents** (`BranchGeneratorConfig.plagiotropism` $p > 0$, lateral generators only):
|
|
127
|
+
- **The plane.** A plagiotropic parent bears its buds in the plane of its tangent $\mathbf{T}_p$ and the horizontal
|
|
128
|
+
$\mathbf{H} = \mathbf{T}_p \times \mathbf{e}_y$ across it. The plane's normal is
|
|
129
|
+
$\mathbf{N} = \mathbf{H} \times \mathbf{T}_p$, which points up.
|
|
130
|
+
- **Ventral knockout.** No bud is emitted into the downward cone of half-angle $p\,\pi/2$.
|
|
131
|
+
- A bud whose own heading points into the cone does not break. That test is about where the bud sits on the
|
|
132
|
+
bough.
|
|
133
|
+
- Nor may fanning, or a turn for clearance, carry a bud's emitted heading into the cone. Each such candidate is
|
|
134
|
+
rejected, and a bud with none left does not break.
|
|
135
|
+
- Contact projection of a child's first segment can still deflect it in afterwards.
|
|
136
|
+
- **Fanning.** The surviving buds' radial direction loses $p\,|\mathbf{H}|$ of its component along $\mathbf{N}$,
|
|
137
|
+
fanning them into the plane. A vertical parent has no such plane, and its children are not fanned.
|
|
138
|
+
- **Which species.** Plagiotropism follows the species' architectural model (Hallé, Oldeman & Tomlinson's architectural models, as listed by Pfisterer (2000, *Mitt. Biol. Bundesanst.* 370) and Millet, Bouchard & Édelin (1999, *Écoscience* 6: 187–203)):
|
|
139
|
+
- **Massart's model** (*Picea*, *Abies*): tiers of plagiotropic branches. The spruce preset sets it.
|
|
140
|
+
- **Rauh's model** (*Pinus*, *Acer*, *Quercus*, *Betula*): branches orthotropic and built like the trunk. Those
|
|
141
|
+
presets set none.
|
|
142
|
+
- **Troll's model** (*Fagus*, *Tilia*, *Ulmus*): every axis plagiotropic. Not among the presets.
|
|
143
|
+
- The knockout is the least sourced part: laterals of a plagiotropic branch lie in its horizontal plane, but no
|
|
144
|
+
*Picea*-specific source was found for the fate of its ventral buds. On spruce it barely acts, since the buds are
|
|
145
|
+
already distichous.
|
|
146
|
+
- **Replaces.** This replaces an undocumented emission rule keyed on the *child's* gravitropism, which biased every
|
|
147
|
+
lateral's buds upward and off its underside.
|
|
148
|
+
- **Pads:** its effect was small (oak 0.750 with it, 0.789 without).
|
|
149
|
+
- **Headings:** its effect was not. Without it, oak has 3.8% of twigs more than 30° below the horizontal against
|
|
150
|
+
1.4% (mean heading y 0.327 against 0.398), and birch 1.2% against 0.6%.
|
|
151
|
+
- **No basis:** Rauh-model branches are orthotropic and branch radially, and the positional bias reported for
|
|
152
|
+
some of them is slight hypotony (lower-side laterals favoured; Millet et al. 1999), not an upward one.
|
|
120
153
|
3. **Stepped Spine Integration with Tropisms, Gnarl, & Splits**:
|
|
121
154
|
- As segment $k \to k+1$ advances by $\Delta s = L_l / N_{\text{seg}}$:
|
|
122
155
|
- **Intrinsic curvature**: Pitch rotation around $\mathbf{S}_k$ by $\Delta \theta_{\text{curve}}(t_k)$ and helical twist around $\mathbf{T}_k$.
|
|
123
156
|
- **Gravitropism (Y-up)**: Bending toward $-\mathbf{e}_y = (0, -1, 0)$ (or $+\mathbf{e}_y$ for negative gravitropism), weighted by mechanical tip compliance $\text{lerp}(0.2, 1.0, t^\gamma)$.
|
|
124
157
|
- **Phototropism**: Steering toward $\text{normalize}(\alpha_{\text{sky}}\mathbf{e}_y + (1-\alpha_{\text{sky}})\mathbf{d}_{\text{radial}})$ to seek sky light and escape interior crown self-shading.
|
|
125
158
|
- **Curl / Simplex Gnarl**: 3D divergence-free `curl_noise_3d` (or `sdnoise3_array`) projected perpendicular to $\mathbf{T}_k$.
|
|
159
|
+
- **Plagiotropism**: a lateral shoot with `plagiotropism` $p$ is steered by $-p\,T_{k,y}\,\mathbf{e}_y$ towards the horizontal. The apical `tip_upcurl` still turns its tip up, so conifer boughs keep their upturned ends.
|
|
160
|
+
- **Straightness**: `straightness` $\lambda$ adds $\lambda(\mathbf{T}_0 - \mathbf{T}_k)$, a pull back towards the heading the branch was given, so strong gnarl does not carry a branch out of its sector. $\mathbf{T}_0$ is the bud's heading. For the fork that continues a split it becomes the heading the split deflected it to, as the other forks aim along their own. It resists every deviation from that heading, droop included.
|
|
126
161
|
- **Space Colonization Pull**: Queries `PointHashGrid3.forEachNear` around $\mathbf{p}_k$, pulling $\mathbf{T}_{k+1}$ toward unclaimed attraction points within radius $d_i$ and marking attraction points within kill radius $d_k$ as consumed.
|
|
127
162
|
- **Sympodial / Dichotomous Forking (`split_probability`, `split_angle`, `split_Spread`)**: At segment $k$, a stem can bifurcate or trifurcate into $M \in \{2, 3\}$ daughter branches that diverge symmetrically in azimuth and pitch.
|
|
128
163
|
- **RMF Transport**: Advances $(\mathbf{R}_k, \mathbf{S}_k) \to (\mathbf{R}_{k+1}, \mathbf{S}_{k+1})$ via Wang et al. (2008) **Double Reflection** with fallback to `tube_frame_transport`.
|
|
@@ -130,6 +165,26 @@ For each recursion level $l \in \{0, \dots, L_{\max}\}$:
|
|
|
130
165
|
- After all branch levels are generated in `skeleton.graph`, a bottom-up post-order pass accumulates cross-sectional area using the Da Vinci / Murray Pipe Model law:
|
|
131
166
|
$$R_{\text{pipe}}(v) = \left( R_{\text{tip}}^\alpha + \sum_{e=(v \to u)} R_{\text{pipe}}(u)^\alpha \right)^{1/\alpha}, \quad \alpha \in [2.0, 2.8]$$
|
|
132
167
|
- The final radius at node $v$ blends the artist-controlled parametric taper curve (`radius_profile: AnimationCurve`) with the physical pipe model via `pipe_model_weight` $\in [0, 1]$.
|
|
168
|
+
5. **Annual Shoot Layer** (`skeleton/tree_skeleton_grow_shoots.js`, `skeleton/shoot_systems_simulate.js`; see
|
|
169
|
+
`CROWN_FILLING_BRIEF_2026_10_26.md`):
|
|
170
|
+
- **Input.** Each `species.shoot_rules` entry (`ShootSystemRule`, its bud zones `ShootBudZone`) grows the
|
|
171
|
+
peripheral twig system on every living branch of its `source` generator, after the pipe-model pass. The twigs are
|
|
172
|
+
branches of generator `target` (short shoots `short_target`), one level below their carrier.
|
|
173
|
+
- **The carrier's growth.** A framework branch is born when its parent's tip passed its seat, at the species'
|
|
174
|
+
`shoot_growth.leader_growth`; it carries `round(age)` annual units over its whole length.
|
|
175
|
+
- **Each season, tree-wide**, under a voxel light field (`ShootLightField`: leaf area, Beer-Lambert from a standard
|
|
176
|
+
overcast sky):
|
|
177
|
+
- Every living axis grows a terminal unit; short shoots survive as their light allows.
|
|
178
|
+
- Last season's units burst their zones' buds (and this season's, sylleptically). Unit lengths are drawn per
|
|
179
|
+
order.
|
|
180
|
+
- New shoots are kept to their light's net yield, `shoot_growth.net_yield(Q)` over the rule's gross yield. A shed
|
|
181
|
+
axis takes everything on it.
|
|
182
|
+
- The wood thickens with what it carries (`ShootGirth`): Table 7 (`d = 0.27 + 0.13 age + 0.02 l` cm) for a unit
|
|
183
|
+
of its age, the pipe model at the species' exponent, and 1 / 0.82 of a lateral where it joins, on twigs,
|
|
184
|
+
carriers and the framework above them.
|
|
185
|
+
- **Avoidance.** A unit grows only where it clears today's wood; a shoot the wood has grown into dies.
|
|
186
|
+
- **The record.** Every carrier and twig records where each of its annual units starts
|
|
187
|
+
(`TreeSkeleton.branch_unit_start_t`), for the foliage pass (§6.1).
|
|
133
188
|
|
|
134
189
|
---
|
|
135
190
|
|
|
@@ -167,17 +222,94 @@ For any lateral branch ($l \ge 1$) attached to a parent branch of radius $R_p$ a
|
|
|
167
222
|
|
|
168
223
|
### 6.1 Phyllotactic Attachment Generator
|
|
169
224
|
Generates `FoliageAttachment` transforms along carrier branches of levels $l \in [l_{\text{min}}, L_{\max}]$:
|
|
170
|
-
- Supports `SpiralGolden` ($137.507764^\circ$), `AlternateDistichous` ($180^\circ$), `Tristichous` ($120^\circ$), `Opposite` ($2\times 180^\circ$), `OppositeDecussate` ($2\times 180^\circ$ with $90^\circ$ alternation), and `Whorled` ($M$ organs per node),
|
|
225
|
+
- Supports `SpiralGolden` ($137.507764^\circ$), `AlternateDistichous` ($180^\circ$), `Tristichous` ($120^\circ$), `Opposite` ($2\times 180^\circ$), `OppositeDecussate` ($2\times 180^\circ$ with $90^\circ$ alternation), and `Whorled` ($M$ organs per node), with nodes spaced evenly over the carrier's leafy span.
|
|
226
|
+
- **Card density is derived, not authored** (`skeleton/foliage_card_density.js`):
|
|
227
|
+
- **The sleeve.** A card leaves the shoot at insertion angle $\alpha$ and reaches $L$, so the shoot wears a foliage
|
|
228
|
+
sleeve of radius $R = L \sin\alpha$.
|
|
229
|
+
- **One leaf per line of sight.** The carrier holds just enough leaf that a line of sight through that sleeve meets
|
|
230
|
+
one leaf on average. By Cauchy's formula the sleeve's mean projected area is a quarter of its surface ($2\pi R$ per
|
|
231
|
+
metre), and a flat leaf's is half its area. So the leaf area is $\pi R$ per metre, and
|
|
232
|
+
$$n = \frac{\pi \sin\alpha \,(1 - v_a)}{S \, s \, \phi \, P}\ \text{cards per metre}.$$
|
|
233
|
+
The terms:
|
|
234
|
+
- $S$ is the side of the species' square card, the size its tile draws its leaf at (`foliage_tile_layout`, §6.3),
|
|
235
|
+
and $s$ the card scale on that shoot.
|
|
236
|
+
- $\phi$ is the atlas's measured leaf coverage (`FoliageAtlasCutout.coverage`).
|
|
237
|
+
- $P$ is the number of planes a card stands up (2 for `CrossCard`, 3 for `TriStarCluster`).
|
|
238
|
+
- $v_a$ is where the tile's leaf attaches (`FoliageTileLayout.anchor_v`): the card's length spans the tile from
|
|
239
|
+
there.
|
|
240
|
+
- **Leafy span.** It starts at the rule's `attach_min`, honoured up to 0.92 (`foliage_leafy_span_start`), for the
|
|
241
|
+
cards and the sail alike.
|
|
242
|
+
- **Rounding.** The expected count is rounded with a golden-ratio dither per (branch, rule), so it is exact on
|
|
243
|
+
average.
|
|
244
|
+
- **Annual units replace the rule.** A branch that records its annual units (`TreeSkeleton.branch_unit_start_t`,
|
|
245
|
+
written by the annual shoot layer, §4.2) carries, on each unit, its leaves (`leaves_per_unit + leaves_per_metre L`,
|
|
246
|
+
times `leaf_survival` at the unit's age; a short shoot `leaves_per_short_shoot` at its tip), in place of the
|
|
247
|
+
density rule (`foliage_unit_card_spans`).
|
|
248
|
+
- **A card a leaf.** Each leaf is a card at its own node along the unit, leaving the shoot at the rule's insertion
|
|
249
|
+
angle and turned by its phyllotaxis. A needle-shoot card draws a stretch of shoot with its needles instead, as
|
|
250
|
+
many as the shoot bears there, and lies along it.
|
|
251
|
+
- **Maturity.** Each card draws its own maturity from its branch.
|
|
252
|
+
- **Wind.** The joint mechanics load the same card on that unit.
|
|
253
|
+
- **Wind.** The joint mechanics take the same $\pi R$ per metre as the foliage's sail. The wind rig and the cards
|
|
254
|
+
agree within 0–3.5% on every preset (size variance and length floors).
|
|
255
|
+
- **Abscission and wilt** (`skeleton/foliage_senescence.js`):
|
|
256
|
+
- **Each tile's onset.** The pigment model ages each atlas tile at its own pace: a tile of maturity $\mu$ is at stage
|
|
257
|
+
$\sigma_k = \sigma(0.80 + 0.36|\mu - 0.35|) + 0.12\sigma^2$ (`foliage_variant_senescence`), and retains
|
|
258
|
+
$1 - \sigma_k(1.36 - \text{shielding})$ of its chlorophyll. Its exposed lamina is bare once $\sigma_k = 1/1.36$.
|
|
259
|
+
`foliage_variant_abscission_onset` solves that for the tree's senescence, $\sigma_0(\mu)$: 0.66 for mature tiles,
|
|
260
|
+
0.73 for juvenile ones and 0.82 at $\mu = 0.35$. No leaf falls or dries before its own tile's onset.
|
|
261
|
+
- **Each card's threshold.** After that, exposure orders the fall. A card's threshold
|
|
262
|
+
$\theta \in [\sigma_0(\mu), 1]$ comes from the mean of its sun exposure ($0.62\,\rho_{\text{shell}} + 0.38\,h_{\text{norm}}$)
|
|
263
|
+
and its position along its shoot. Outer and apical leaves fall first, and the crown is bare at $\sigma = 1$.
|
|
264
|
+
- **Dryness.** Between its onset and its fall the card dries: $d = (\sigma - \sigma_0)/(\theta - \sigma_0)$.
|
|
265
|
+
- The mesh builder takes a folding card (`FoldedVCard`, `RibbedFrond`, `CutoutHull`) towards a leaf with no turgor:
|
|
266
|
+
the fold closes towards $\pi/2$, the arch goes to 0, and the droop goes to 1. `CrossCard` and `TriStarCluster`
|
|
267
|
+
have no fold and do not wilt.
|
|
268
|
+
- A card just before its fall is nearly shut, a valid sliver.
|
|
269
|
+
- **Wind.** The joint mechanics shed the same leaves from their sail. They judge the expected leaf (no jitter) at each
|
|
270
|
+
segment's middle.
|
|
171
271
|
- **Heliotropic & Gravitropic Orientation**:
|
|
172
272
|
- Reorients each leaf/frond basis $(\mathbf{F}, \mathbf{U}, \mathbf{W})$ so its adaxial normal $\mathbf{U}$ tilts toward the sky + canopy-outward light vector (`phototropism` $\in [0, 1]$) while its forward tip $\mathbf{F}$ droops under `gravitropism` $\in [-1, 1]$, with seeded angular jitter to prevent specular aliasing.
|
|
173
273
|
|
|
174
274
|
### 6.2 Foliage Topologies
|
|
175
275
|
Supports 5 production real-time foliage card/mesh archetypes:
|
|
176
|
-
1. **`FoldedVCard
|
|
177
|
-
2. **`CrossCard` (
|
|
178
|
-
3. **`TriStarCluster` (
|
|
276
|
+
1. **`FoldedVCard`**: $2 \times 2$ or $2 \times 3$ grid with transverse V-fold angle $\beta_{\text{fold}}$, longitudinal midrib arch $h_{\text{arch}} \sin(\pi v)$, and tip camber $-h_{\text{camber}} v^2$. Never appears razor-flat at grazing view angles.
|
|
277
|
+
2. **`CrossCard` (needle shoot)**: Two orthogonal intersecting V-cards rotated by $90^\circ$ around the shoot axis $\mathbf{F}$; each plane draws the needles in its sector round the shoot (§6.3).
|
|
278
|
+
3. **`TriStarCluster` (needle shoot)**: Three cards arranged at $60^\circ$ star angles, each drawing its sector's needles.
|
|
179
279
|
4. **`RibbedFrond` (Palms, Ferns, Cycads, Weeping Boughs)**: Multi-segment curved Cubic Hermite frond spine with RMF transport, longitudinal V-fold variation, and width profile $W(t) = W_{\max} \sin(\pi t^{p_w})$.
|
|
180
|
-
5. **`
|
|
280
|
+
5. **`CutoutHull` (Fitted Alpha-Bound Card, the broadleaves' leaf)**: the convex hull of everything its atlas tile
|
|
281
|
+
draws, reduced to 6 vertices and fanned around a midrib vertex.
|
|
282
|
+
- **Shape.** Each half turns about the midrib by `fold_angle`, and the card arches and droops along its length like
|
|
283
|
+
a frond spine.
|
|
284
|
+
- **Fitting.** `make_foliage_material` fits the hulls while it synthesizes the atlas (`FoliageAtlasCutout`):
|
|
285
|
+
- Each covered texel row contributes the outer corners of its first and last texel that has any alpha.
|
|
286
|
+
- `convex_hull_monotone_2d` hulls those points.
|
|
287
|
+
- `convex_hull_fixed_count_2d_relaxation` reduces the hull to 6 vertices inside the tile, inset by half a texel
|
|
288
|
+
(its `bounds`), so no corner reaches the atlas neighbour.
|
|
289
|
+
- When no edge can be removed without leaving the tile, the unbounded fit is clipped to the tile
|
|
290
|
+
(`polygon2_clip_axis_halfplane`) and relaxed again.
|
|
291
|
+
- If that stalls too, the hull is the silhouette's bounding box as a hexagon. It is looser, but it holds every drawn
|
|
292
|
+
texel. Clamping the unbounded fit's corners instead would cut the leaf.
|
|
293
|
+
- **Result.** A willow's lanceolate leaf is cut far tighter than a hazel's broad one (`foliage_atlas_cutout.spec`).
|
|
294
|
+
- **Custom material.** With a caller's own material, the cards cover whole tiles.
|
|
295
|
+
|
|
296
|
+
### 6.3 Leaf Architecture and the Atlas Tile
|
|
297
|
+
Every tile draws the species' own leaf at its true size (`material/leaf_geometry.js`, `material/foliage_tile.js`;
|
|
298
|
+
`LEAF_ARCHITECTURE_BRIEF_2026_10_26.md`):
|
|
299
|
+
- **The leaf, as floras describe it** (`LeafArchitecture`, in the terms of Ellis et al. 2009, *Manual of Leaf
|
|
300
|
+
Architecture*): blade length and length/width ratio, where it is widest, apex and base angles and shapes, pinnate or
|
|
301
|
+
palmate lobes with their sinus depth, teeth a centimetre and their depth and order, secondary veins and their
|
|
302
|
+
angle, petiole length; a compound leaf's leaflets and rachis. Each preset cites its flora.
|
|
303
|
+
- **The outline** is a monotone cubic Hermite envelope through the base, the base angle's point a quarter of the way up,
|
|
304
|
+
the widest point, the apex angle's point and the apex; rounded ends are arcs, acuminate ones concave. A pinnately
|
|
305
|
+
lobed blade is a body out to the sinus floors plus a rounded lobe along each secondary vein; a palmate one is a lobe
|
|
306
|
+
per primary vein over a body; teeth are offset along the outline's normal. All contours wind the same way, so
|
|
307
|
+
`polygon2_rasterize_coverage` fills their union by the nonzero rule with exact coverage across each row.
|
|
308
|
+
- **The tile** draws the mature leaf filling it within a 2% margin, attached at the bottom middle; younger leaves are
|
|
309
|
+
smaller. The card is that tile at that scale: its size is the leaf's. The resolution draws the leaf's finest feature
|
|
310
|
+
(a tooth, a sinus) four texels across and its stems two, so they survive the alpha test.
|
|
311
|
+
- **Needle shoots** draw a stretch of shoot as long as a needle, its needles shared among the card's planes, each
|
|
312
|
+
plane showing those in its sector round the shoot, foreshortened by their azimuth.
|
|
181
313
|
|
|
182
314
|
---
|
|
183
315
|
|
|
@@ -187,6 +319,11 @@ Supports 5 production real-time foliage card/mesh archetypes:
|
|
|
187
319
|
- **Per-Vertex Canopy AO (`StandardAttributes.Color`)**:
|
|
188
320
|
- Combines macro crown ellipsoid depth $AO_{\text{crown}}(\mathbf{v}) \in [AO_{\text{core}}, 1.0]$ with local hierarchy depth $AO_{\text{local}}(v) \in [0.7, 1.0]$ (darkening inner branch crotches and petiole bases while brightening outer sun-exposed tips).
|
|
189
321
|
- Multiplied with optional per-cluster hue/value jitter in `StandardAttributes.Color` (`vec3<f32>`), which `StandardShadeMaterial` automatically multiplies with `texture_albedo` in the G-buffer pass.
|
|
322
|
+
- **Tint headroom.** Vertex colours are encoded as `unorm8`, so on their own they can only darken. Each card's tint
|
|
323
|
+
(`FoliageAttachmentSet.tints`) is free to exceed 1. The builder writes `tint / tint_scale`, where `tint_scale` is
|
|
324
|
+
the largest tint channel, and the foliage material's `diffuse_color` (the shader's `albedo_color`) carries
|
|
325
|
+
`tint_scale` back. The product is exactly `albedo · tint · AO`. Across the presets `tint_scale` is about 1.1, and
|
|
326
|
+
about half of all tint channels exceed 1.
|
|
190
327
|
- **Spherized / Puffed Foliage Normals (`StandardAttributes.Normal`)**:
|
|
191
328
|
- Blends the geometric card normal $\mathbf{n}_{\text{card}}$ with the canopy-outward normal $\text{normalize}(\mathbf{v} - \mathbf{C}_{\text{crown}})$ by `normal_puffiness` $\in [0, 0.85]$ before running `geometry.ensureTangents()`, giving leaf clusters soft volumetric canopy lighting.
|
|
192
329
|
|
|
@@ -212,8 +349,8 @@ Meep's visibility-buffer renderer (`Shade`) deforms `MeshletGeometry` on the GPU
|
|
|
212
349
|
When the caller does not pass custom `bark_material` or `foliage_material`, the system synthesizes studio-quality procedural PBR textures using `Sampler2D` $\to$ `ShadeImage.fromSampler2D` $\to$ `ShadeTexture.from`:
|
|
213
350
|
1. **`make_bark_material(config)`**:
|
|
214
351
|
- Generates tileable (`TextureWrapType.Repeat`) bark **Albedo** (fissured ridges, lenticels/stripes for birch, warm heartwood/moss undertones), **Tangent-Space Normal Map** (derived analytically from height gradients), and **ORM Map** (`R`: fissure occlusion, `G`: micro-roughness, `B`: 0 metalness) on a `StandardShadeMaterial` (`TransparencyMode.Opaque`, `ShadeDrawSide.Front`).
|
|
215
|
-
2. **`make_foliage_material(
|
|
216
|
-
- Generates
|
|
352
|
+
2. **`make_foliage_material(species)`**:
|
|
353
|
+
- Generates the species' leaf (or needle shoot) **Albedo + Alpha Cutout** texture from its `LeafArchitecture` (§6.3: outline coverage, midvein and secondary veins, petiole, premultiplied RGBA compatible with Shade's `albedo_unpremultiply` and hashed alpha test), **Tangent-Space Normal Map** (camber, vein relief, bullation), and **ORM Map** on a `StandardShadeMaterial` (`TransparencyMode.AlphaTested`, `ShadeDrawSide.Double`, `transmission_factor: 0`).
|
|
217
354
|
|
|
218
355
|
### 7.4 Multi-LOD Chain with Area-Compensated Foliage Decimation
|
|
219
356
|
Generates a configurable $N$-level LOD chain (default 4 levels: `LOD0`, `LOD1`, `LOD2`, `LOD3`):
|
|
@@ -239,10 +376,13 @@ src/generation/foliage/
|
|
|
239
376
|
config/
|
|
240
377
|
CrownEnvelopeType.js
|
|
241
378
|
PhyllotaxisMode.js
|
|
242
|
-
FoliageCardType.js
|
|
379
|
+
FoliageCardType.js
|
|
243
380
|
FoliageBarkType.js
|
|
244
381
|
TreePreset.js
|
|
245
|
-
|
|
382
|
+
BranchGeneratorConfig.js
|
|
383
|
+
BranchSpawnRule.js
|
|
384
|
+
FoliageSpawnRule.js
|
|
385
|
+
ShootSystemRule.js
|
|
246
386
|
CrownConfig.js
|
|
247
387
|
FoliageConfig.js
|
|
248
388
|
BarkMaterialConfig.js
|
|
@@ -258,17 +398,27 @@ src/generation/foliage/
|
|
|
258
398
|
spine_frame_double_reflection.js (+ .spec.js)
|
|
259
399
|
tree_skeleton_grow.js (+ .spec.js)
|
|
260
400
|
tree_skeleton_compute_pipe_radii.js (+ .spec.js)
|
|
401
|
+
shoot_demography.js (+ .spec.js)
|
|
402
|
+
tree_skeleton_grow_shoots.js (+ .spec.js)
|
|
261
403
|
tree_skeleton_assign_skin_joints.js (+ .spec.js)
|
|
404
|
+
tree_skeleton_grow_growth_modifiers.spec.js
|
|
405
|
+
foliage_card_density.js
|
|
406
|
+
foliage_senescence.js
|
|
262
407
|
mesh/
|
|
263
408
|
branch_collar_project.js (+ .spec.js)
|
|
264
409
|
branch_ring_triangulate.js (+ .spec.js)
|
|
265
410
|
tree_mesh_build_bark.js (+ .spec.js)
|
|
266
|
-
foliage_collect_attachments.js (+ .spec.js)
|
|
267
|
-
|
|
411
|
+
foliage_collect_attachments.js (+ .spec.js, _density.spec.js)
|
|
412
|
+
foliage_seasons.spec.js
|
|
413
|
+
tree_mesh_build_foliage.js (+ .spec.js, _cutout.spec.js)
|
|
268
414
|
tree_mesh_apply_canopy_ao.js (+ .spec.js)
|
|
269
415
|
material/
|
|
270
416
|
make_bark_material.js (+ .spec.js)
|
|
271
417
|
make_foliage_material.js (+ .spec.js)
|
|
418
|
+
compute_foliage_variant_atlas_layout.js
|
|
419
|
+
foliage_leaf_silhouette.js
|
|
420
|
+
FoliageAtlasCutout.js
|
|
421
|
+
foliage_atlas_cutout.js (+ .spec.js)
|
|
272
422
|
animation/
|
|
273
423
|
build_tree_wind_rig.js (+ .spec.js)
|
|
274
424
|
asset/
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Leaf Architecture
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
The oak's cards did not look like oak leaves (Alex, 2026-10-26: "What the fuck is that?"). Two causes, both hacks:
|
|
6
|
+
|
|
7
|
+
- **The leaf outline was code, not botany.** `foliage_leaf_silhouette.js` switched on a string, `"lobed"` (a ±28% sine
|
|
8
|
+
ripple, "oak-like"), `"serrated"` (a sawtooth), `"palmate"` (a cosine), each with hand-picked constants. The oak's
|
|
9
|
+
`"lobed"` blade was widest near its base, with shallow wavy edges: a Christmas tree.
|
|
10
|
+
- **A whole shoot was painted flat into one texture.** The `"rosette"` arrangement drew 11 leaves from one point,
|
|
11
|
+
fanned over ±83°, each three-quarters as wide as long. They merged into one blob with 11 tips. A `TriStarCluster`
|
|
12
|
+
stood three of those on crossing planes, which is the star in the screenshot. Meanwhile the simulation grows the
|
|
13
|
+
real shoots, so the tile duplicated the shoot geometry and contradicted it.
|
|
14
|
+
|
|
15
|
+
Fixing the oak's outline alone would have kept both hacks.
|
|
16
|
+
|
|
17
|
+
## Principle
|
|
18
|
+
|
|
19
|
+
- **A leaf is data, described as floras describe it.** Ellis et al. (2009), *Manual of Leaf Architecture*, gives the
|
|
20
|
+
vocabulary; each preset cites its flora.
|
|
21
|
+
- **A card is one leaf, on its shoot.** Each leaf is a card at its own node, leaving the shoot at the rule's insertion
|
|
22
|
+
angle and turned by its phyllotaxis.
|
|
23
|
+
- **Needles stay shoot cards.** Pine bears 1,560 needles per metre and spruce 2,450 (sourced in the presets). A card
|
|
24
|
+
per needle is out of reach, and the needle shoot is the unit those papers measure.
|
|
25
|
+
|
|
26
|
+
## Design
|
|
27
|
+
|
|
28
|
+
- **`LeafArchitecture`** (`FoliageMaterialConfig.leaf`):
|
|
29
|
+
- blade length, length/width ratio, where it is widest;
|
|
30
|
+
- apex and base angle and shape (`LeafApexShape`, `LeafBaseShape`; the angles measured as Ellis et al. define them,
|
|
31
|
+
a quarter of the blade's length from the tip or the base);
|
|
32
|
+
- lobation (`LeafLobation`), lobes, sinus depth, palmate spread and lateral lobe length;
|
|
33
|
+
- teeth per cm, tooth depth and order;
|
|
34
|
+
- secondary veins and their angle;
|
|
35
|
+
- petiole length;
|
|
36
|
+
- a compound leaf's leaflets and rachis.
|
|
37
|
+
- **`leaf_geometry`** turns that into outline contours, veins and stems in metres:
|
|
38
|
+
- **Envelope:** a monotone cubic Hermite (Fritsch-Carlson) through the base, the base angle's point, the widest point,
|
|
39
|
+
the apex angle's point and the apex. The shapes set the end slopes. A rounded end is an elliptic arc; an acuminate
|
|
40
|
+
one is shallow, so the margin is concave near the tip.
|
|
41
|
+
- **Pinnate lobes:** the blade reaches only to the sinus floor, `1 - sinus_depth` of the outline's width. Each lateral
|
|
42
|
+
lobe is a rounded blade of its own along its secondary vein (so it leans by the vein's angle), out to the outline.
|
|
43
|
+
The veins leave the midvein evenly spaced.
|
|
44
|
+
- **Palmate lobes:** a blade per primary lobe, radiating across `lobe_spread`, over a body to the sinus floors.
|
|
45
|
+
- **Base lobes:** cordate and lobate bases are a cubic Bezier from the petiole sinus round the basal lobe, solved to
|
|
46
|
+
reach exactly `base_lobe_depth` below the petiole.
|
|
47
|
+
- **Teeth:** offset along the outline's normal, spaced along the untoothed margin, with a second order a third the
|
|
48
|
+
size.
|
|
49
|
+
- **Union:** every contour winds the same way, so the union of lobes, leaflets and petiole is filled by the nonzero
|
|
50
|
+
rule (`polygon2_rasterize_coverage`, exact across each row, 4 samples down it).
|
|
51
|
+
- **`foliage_tile_layout`** (one place for every consumer):
|
|
52
|
+
- The mature leaf fills the tile within a 2% margin, attached at the bottom middle. Every tile draws at that scale,
|
|
53
|
+
so the card's size in metres is the leaf's (`card_size`).
|
|
54
|
+
- **Resolution:** the finest feature (a tooth, a sinus) is drawn 4 texels across. The narrowest stem is drawn 2
|
|
55
|
+
texels across, so wherever it falls it covers a whole texel and survives the alpha test.
|
|
56
|
+
- **Needle shoots:** a stretch of shoot as long as a needle, with the needles the shoot bears there
|
|
57
|
+
(`leaves_per_metre`), shared among the card's planes. Each plane draws the needles in its sector round the shoot,
|
|
58
|
+
foreshortened by their azimuth.
|
|
59
|
+
- **`foliage_tile_raster`:**
|
|
60
|
+
- Coverage, veins stamped near each segment, distance to the margin and to the midvein by chamfer, camber,
|
|
61
|
+
bullation, and the petiole.
|
|
62
|
+
- The pigment, senescence and normal code of `make_foliage_material` is unchanged. It now skips the texels the leaf
|
|
63
|
+
leaves empty, which keep the dilated fill.
|
|
64
|
+
- **Cards:**
|
|
65
|
+
- **Broadleaves:** a card per leaf. A short shoot's `leaves_per_short_shoot` sit at its tip. The presets draw
|
|
66
|
+
`CutoutHull` cards.
|
|
67
|
+
- **Needle cards** lie along the shoot.
|
|
68
|
+
- **Density path:** branches not grown by annual units keep it, on the layout's card size and anchor.
|
|
69
|
+
|
|
70
|
+
## Sources per species
|
|
71
|
+
|
|
72
|
+
| preset | leaf | sources | estimated, not found |
|
|
73
|
+
| :--- | :--- | :--- | :--- |
|
|
74
|
+
| oak (*Quercus robur*) | mean blade 10.6 and 12.0 cm; L/W 1.8, 1.64; width 0.81-0.85 of max at 0.5 L, 0.47-0.50 at 0.9 L; petiole 7.4-8.0% of blade | Boratyński et al. 2008, *Silva Fennica* 42: 115-124, Table 4. Fitted: widest at 0.675, apex angle 1.2, base 0.8 rad (both widths within 0.01) | auricle size, secondary angle |
|
|
75
|
+
| | obovate; apex broadly rounded; sinuses 1/3-7/8 to midrib; entire; 5-7 secondaries | FNA vol. 3 | |
|
|
76
|
+
| | 5-7 lobes a side | Flora of China | |
|
|
77
|
+
| | up to 5 pairs; auricles usually strong | BSBI Plant Crib | |
|
|
78
|
+
| birch (*Betula pendula*) | 3-7 × 2.5-5 cm, ovate-rhombic, acuminate, cuneate, doubly serrate | FNA | apex and base angles, teeth (1.3 a cm, 1.5 mm), widest point |
|
|
79
|
+
| | 6-8 lateral veins; petiole 2-3 cm | FoC | |
|
|
80
|
+
| | 2 leaves a short shoot | Maillette 1982 | |
|
|
81
|
+
| willow (*Salix babylonica*) | 90-160 × 5-20 mm, L/W 5.5-10.5, acuminate, cuneate, serrulate; petiole 7-9 mm | FNA vol. 7 | angles, teeth (5 a cm, 0.3 mm), veins |
|
|
82
|
+
| maple (*Acer rubrum*) | 6.8 cm, 39 cm² | Wilson 1966 | lobe outline, lateral lobe length 0.85, teeth (3 a cm, 1.5 mm) |
|
|
83
|
+
| | 3 lobes; lateral axes 73-86° apart; midlobe 46-56% of blade; petiole 60-114% of blade; 2 leaf pairs a short shoot | Critchfield 1971 | |
|
|
84
|
+
| | doubly serrate | Gleason & Cronquist | |
|
|
85
|
+
| | base truncate to cordate | Trees and Shrubs Online | |
|
|
86
|
+
| shrub (*Corylus avellana*) | 5-12 × 4-12 cm, abruptly acuminate, narrowly cordate, doubly serrate, ≤ 8 vein pairs | FNA | angles, base lobe depth, teeth (0.7 a cm, 2.5 mm) |
|
|
87
|
+
| | petiole 6-12 mm | Trees and Shrubs Online | |
|
|
88
|
+
| | 8 cm gives the 41 cm² of a sun leaf | Catoni et al. 2015 | |
|
|
89
|
+
| pine, spruce needles | 52 mm [Niinemets & Lukjanova 2003]; spruce's 18 mm was already chosen | | widths 1.6 and 1 mm; needle angle 0.6 rad |
|
|
90
|
+
| palm, fern | no species named: the old frond's sizes are kept | | everything |
|
|
91
|
+
|
|
92
|
+
The botanical data was gathered by a research subagent from efloras.org (FNA, FoC), BSBI, VicFlora, Go Botany, Trees
|
|
93
|
+
and Shrubs Online, SEINet and the papers above. Its quotes and URLs are in the session's scratchpad (`leaf/`).
|
|
94
|
+
floranorthamerica.org refused access, and HAL (Kremer et al. 2002) is behind a bot check.
|
|
95
|
+
|
|
96
|
+
## Measured
|
|
97
|
+
|
|
98
|
+
*Seed 1337 unless noted; the "before" figures are from 49845ff00.*
|
|
99
|
+
|
|
100
|
+
**Atlas, from the drawn tiles:**
|
|
101
|
+
|
|
102
|
+
| preset | resolution | card | coverage | one leaf |
|
|
103
|
+
| :--- | ---: | ---: | ---: | ---: |
|
|
104
|
+
| oak | 128 | 12.7 cm | 0.208 | 33 cm² |
|
|
105
|
+
| birch | 256 | 7.8 cm | 0.174 | 10.6 cm² |
|
|
106
|
+
| willow | 512 | 13.9 cm | 0.073 | 14 cm² |
|
|
107
|
+
| maple | 512 | 13.2 cm | 0.213 | 37 cm² |
|
|
108
|
+
| shrub | 128 | 9.3 cm | 0.522 | 45 cm² |
|
|
109
|
+
| pine | 256 | 9.8 cm (81 needles) | | |
|
|
110
|
+
| spruce | 256 | 3.4 cm (44 needles) | | |
|
|
111
|
+
| palm | 128 | | | |
|
|
112
|
+
| fern | 128 | | | |
|
|
113
|
+
|
|
114
|
+
Leaf areas against the sources:
|
|
115
|
+
- maple: 37 cm² against Wilson's 39;
|
|
116
|
+
- hazel: 45 cm² against Catoni's 41;
|
|
117
|
+
- birch: 10.6 cm² against about 11 from FNA's sizes.
|
|
118
|
+
|
|
119
|
+
**Cost:** cards, LOD0 triangles, and `generate_tree` time with the LOD0 meshes.
|
|
120
|
+
|
|
121
|
+
| preset | cards | foliage tris | bark tris | generate + LOD0 |
|
|
122
|
+
| :--- | ---: | ---: | ---: | ---: |
|
|
123
|
+
| oak | 25,622 | 153,732 | 81,587 | 0.77 + 0.06 s |
|
|
124
|
+
| pine | 3,554 | 21,324 | 39,817 | 0.71 + 0.03 s |
|
|
125
|
+
| birch | 63,909 | 383,454 | 454,735 | 1.73 + 0.56 s |
|
|
126
|
+
| willow | 113,001 | 678,006 | 410,091 | 1.81 + 0.46 s |
|
|
127
|
+
| maple | 13,008 | 78,048 | 37,774 | 1.16 + 0.05 s |
|
|
128
|
+
| spruce | 176,311 | 705,244 | 1,085,114 | 3.12 + 1.23 s |
|
|
129
|
+
| shrub | 16,976 | 101,856 | 62,817 | 0.52 + 0.05 s |
|
|
130
|
+
|
|
131
|
+
**Crowns,** measured with `foliage_measure_leaf_area` and `tree_crown_opacity`; "before" is 49845ff00:
|
|
132
|
+
|
|
133
|
+
| preset | leaf m² (before) | crown LAI | side density | side transparency | below density | below transparency |
|
|
134
|
+
| :--- | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
135
|
+
| oak | 89.4 (90.9) | 3.11 | 0.50 | 0.42 | 0.58 | 0.27 |
|
|
136
|
+
| pine | 15.7 (35.0) | 0.74 | 0.34 | 0.64 | 0.35 | 0.62 |
|
|
137
|
+
| birch | 70.4 (64.5) | 6.77 | 0.56 | 0.33 | 0.75 | 0.12 |
|
|
138
|
+
| willow | 232.6 (136.3) | 6.43 | 0.75 | 0.18 | 0.74 | 0.19 |
|
|
139
|
+
| maple | 50.7 (36.3) | 1.97 | 0.41 | 0.42 | 0.42 | 0.32 |
|
|
140
|
+
| spruce | 78.4 (117.8) | 3.03 | 0.33 | 0.31 | 0.42 | 0.29 |
|
|
141
|
+
| shrub | 62.5 (57.8) | 4.52 | 0.63 | 0.22 | 0.64 | 0.16 |
|
|
142
|
+
|
|
143
|
+
- **Pine and spruce lost leaf area** because their old tiles overdrew. Every plane of a card drew all of its needles,
|
|
144
|
+
three times over on pine, and wider than the needles are. Now each needle is drawn once at its width.
|
|
145
|
+
- **Willow gained,** its lanceolate leaves replacing a frond drawing. Its transparency, 0.18, is near FIA's 15%.
|
|
146
|
+
|
|
147
|
+
## Open (measured, not argued)
|
|
148
|
+
|
|
149
|
+
- **Card counts rose where a card used to hold several leaves:** birch 5×, willow 9×, oak 11×. Pine and spruce rose
|
|
150
|
+
2.4×, because a needle card now covers one needle length of shoot, not 2.4. That stretch is chosen, not sourced.
|
|
151
|
+
- **Estimates:** the angles, tooth sizes and widest points the floras do not give are marked in each preset.
|
|
152
|
+
- **Palm and fern** name no species, so their leaves are not sourced.
|
|
153
|
+
- **Wind sail:**
|
|
154
|
+
- `TreeWindConfig.elastic_modulus` is fitted to the oak, whose leaf area moved by 2% (90.9 to 89.4 m²); it was not
|
|
155
|
+
refit.
|
|
156
|
+
- Pine's and spruce's sails fell with their leaf area (to 0.45 and 0.67), so they will sway less. That sway is not
|
|
157
|
+
measured.
|
|
158
|
+
- **Transparency:** every crown but willow's is still far above FIA's 15% transparency.
|