@woosh/meep-engine 3.51.0 → 3.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/engine/ecs/animation/Animation.d.ts +4 -25
- package/src/engine/ecs/animation/Animation.d.ts.map +1 -1
- package/src/engine/ecs/animation/Animation.js +9 -41
- package/src/engine/ecs/ik/IKGoalSystem.d.ts +4 -5
- package/src/engine/ecs/ik/IKGoalSystem.d.ts.map +1 -1
- package/src/engine/ecs/ik/IKGoalSystem.js +4 -6
- package/src/engine/graphics/ecs/mesh/assetTypeByPath.js +1 -1
- package/src/engine/graphics3/AnimationGraphSystem.d.ts +9 -22
- package/src/engine/graphics3/AnimationGraphSystem.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationGraphSystem.js +58 -203
- package/src/engine/graphics3/AnimationSystem.d.ts +7 -18
- package/src/engine/graphics3/AnimationSystem.d.ts.map +1 -1
- package/src/engine/graphics3/AnimationSystem.js +62 -243
- package/src/engine/graphics3/FoliageWindSystem.d.ts +67 -0
- package/src/engine/graphics3/FoliageWindSystem.d.ts.map +1 -0
- package/src/engine/graphics3/FoliageWindSystem.js +257 -0
- package/src/engine/graphics3/GPUFluidSystem.d.ts +7 -0
- package/src/engine/graphics3/GPUFluidSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUFluidSystem.js +39 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +0 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +19 -5
- package/src/engine/graphics3/animation/AnimationClips.d.ts +107 -13
- package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -1
- package/src/engine/graphics3/animation/AnimationClips.js +207 -10
- package/src/engine/graphics3/animation/AnimationClipsSink.d.ts +89 -0
- package/src/engine/graphics3/animation/AnimationClipsSink.d.ts.map +1 -0
- package/src/engine/graphics3/animation/AnimationClipsSink.js +205 -0
- package/src/engine/graphics3/animation/FoliageWindRigs.d.ts +43 -0
- package/src/engine/graphics3/animation/FoliageWindRigs.d.ts.map +1 -0
- package/src/engine/graphics3/animation/FoliageWindRigs.js +69 -0
- package/src/engine/graphics3/animation/write_clip_playback.d.ts +17 -11
- package/src/engine/graphics3/animation/write_clip_playback.d.ts.map +1 -1
- package/src/engine/graphics3/animation/write_clip_playback.js +36 -27
- package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
- package/src/engine/graphics3/decal/GPUDecalRenderer.js +8 -6
- package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_decal_composite.js +11 -5
- package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts +7 -7
- package/src/engine/graphics3/pose/collect_entity_playbacks.d.ts.map +1 -1
- package/src/engine/graphics3/pose/collect_entity_playbacks.js +14 -15
- package/src/engine/graphics3/prefab/Prefab.d.ts +6 -0
- package/src/engine/graphics3/prefab/Prefab.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/Prefab.js +169 -162
- package/src/engine/graphics3/prefab/prefab_compile.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/prefab_compile.js +369 -334
- package/src/engine/graphics3/prefab/prefab_instantiate.d.ts.map +1 -1
- package/src/engine/graphics3/prefab/prefab_instantiate.js +43 -2
- package/src/engine/graphics3/terrain/chunk_terrain_material_surface.js +2 -2
- package/src/engine/physics/ecs/ContactProbeSystem.d.ts +2 -3
- package/src/engine/physics/ecs/ContactProbeSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/ContactProbeSystem.js +2 -4
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/sound/simulation/PROBE_PLACEMENT.md +4 -4
- package/src/engine/sound/simulation/README.md +1 -1
- package/src/engine/sound/simulation/probe/bakeProbeField.d.ts +22 -8
- package/src/engine/sound/simulation/probe/bakeProbeField.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/bakeProbeField.js +60 -15
- package/src/engine/sound/simulation/probe/bakeProbeReflectors.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/bakeProbeReflectors.js +19 -23
- package/src/engine/sound/simulation/probe/probe_sdf_grid.d.ts +63 -17
- package/src/engine/sound/simulation/probe/probe_sdf_grid.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/probe_sdf_grid.js +67 -17
- package/src/generation/foliage/FOLIAGE_DESIGN.md +318 -0
- package/src/generation/foliage/FOLIAGE_PLAN.md +198 -0
- package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +20 -0
- package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -0
- package/src/generation/foliage/animation/build_tree_wind_rig.js +108 -0
- package/src/generation/foliage/asset/TreeAsset.d.ts +86 -0
- package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -0
- package/src/generation/foliage/asset/TreeAsset.js +111 -0
- package/src/generation/foliage/asset/TreeLODAsset.d.ts +115 -0
- package/src/generation/foliage/asset/TreeLODAsset.d.ts.map +1 -0
- package/src/generation/foliage/asset/TreeLODAsset.js +346 -0
- package/src/generation/foliage/asset/generate_tree.d.ts +15 -0
- package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -0
- package/src/generation/foliage/asset/generate_tree.js +93 -0
- package/src/generation/foliage/asset/place_tree.d.ts +82 -0
- package/src/generation/foliage/asset/place_tree.d.ts.map +1 -0
- package/src/generation/foliage/asset/place_tree.js +194 -0
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts +120 -0
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/BarkMaterialConfig.js +250 -0
- package/src/generation/foliage/config/BranchLevelConfig.d.ts +288 -0
- package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/BranchLevelConfig.js +536 -0
- package/src/generation/foliage/config/CrownConfig.d.ts +100 -0
- package/src/generation/foliage/config/CrownConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/CrownConfig.js +186 -0
- package/src/generation/foliage/config/CrownEnvelopeType.d.ts +16 -0
- package/src/generation/foliage/config/CrownEnvelopeType.d.ts.map +1 -0
- package/src/generation/foliage/config/CrownEnvelopeType.js +17 -0
- package/src/generation/foliage/config/FoliageCardType.d.ts +12 -0
- package/src/generation/foliage/config/FoliageCardType.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageCardType.js +18 -0
- package/src/generation/foliage/config/FoliageConfig.d.ts +151 -0
- package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageConfig.js +283 -0
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +90 -0
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageMaterialConfig.js +181 -0
- package/src/generation/foliage/config/PhyllotaxisMode.d.ts +13 -0
- package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -0
- package/src/generation/foliage/config/PhyllotaxisMode.js +20 -0
- package/src/generation/foliage/config/TreeLODConfig.d.ts +87 -0
- package/src/generation/foliage/config/TreeLODConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/TreeLODConfig.js +211 -0
- package/src/generation/foliage/config/TreePreset.d.ts +16 -0
- package/src/generation/foliage/config/TreePreset.d.ts.map +1 -0
- package/src/generation/foliage/config/TreePreset.js +17 -0
- package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +109 -0
- package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/TreeSpeciesConfig.js +400 -0
- package/src/generation/foliage/config/TreeWindConfig.d.ts +84 -0
- package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -0
- package/src/generation/foliage/config/TreeWindConfig.js +157 -0
- package/src/generation/foliage/index.d.ts +38 -0
- package/src/generation/foliage/index.d.ts.map +1 -0
- package/src/generation/foliage/index.js +43 -0
- package/src/generation/foliage/material/make_bark_material.d.ts +37 -0
- package/src/generation/foliage/material/make_bark_material.d.ts.map +1 -0
- package/src/generation/foliage/material/make_bark_material.js +802 -0
- package/src/generation/foliage/material/make_foliage_material.d.ts +14 -0
- package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -0
- package/src/generation/foliage/material/make_foliage_material.js +359 -0
- package/src/generation/foliage/mesh/branch_collar_project.d.ts +42 -0
- package/src/generation/foliage/mesh/branch_collar_project.d.ts.map +1 -0
- package/src/generation/foliage/mesh/branch_collar_project.js +203 -0
- package/src/generation/foliage/mesh/branch_ring_triangulate.d.ts +35 -0
- package/src/generation/foliage/mesh/branch_ring_triangulate.d.ts.map +1 -0
- package/src/generation/foliage/mesh/branch_ring_triangulate.js +72 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +80 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.js +502 -0
- package/src/generation/foliage/mesh/tree_mesh_apply_canopy_ao.d.ts +19 -0
- package/src/generation/foliage/mesh/tree_mesh_apply_canopy_ao.d.ts.map +1 -0
- package/src/generation/foliage/mesh/tree_mesh_apply_canopy_ao.js +150 -0
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts +55 -0
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -0
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1047 -0
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +21 -0
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -0
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +415 -0
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts +13 -0
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -0
- package/src/generation/foliage/presets/make_tree_species_preset.js +837 -0
- package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +443 -0
- package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/TreeSkeleton.js +1100 -0
- package/src/generation/foliage/skeleton/crown_envelope_evaluate.d.ts +27 -0
- package/src/generation/foliage/skeleton/crown_envelope_evaluate.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/crown_envelope_evaluate.js +121 -0
- package/src/generation/foliage/skeleton/spine_frame_double_reflection.d.ts +32 -0
- package/src/generation/foliage/skeleton/spine_frame_double_reflection.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/spine_frame_double_reflection.js +87 -0
- package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +33 -0
- package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +205 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts +14 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +179 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +18 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -0
- package/src/generation/foliage/skeleton/tree_skeleton_grow.js +1104 -0
- package/src/shade/playground/additive_blending/index.html +197 -0
- package/src/shade/playground/additive_blending/main.d.ts +2 -0
- package/src/shade/playground/additive_blending/main.d.ts.map +1 -0
- package/src/shade/playground/additive_blending/main.js +529 -0
- package/src/shade/playground/foliage_wind/README.md +18 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts +127 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -0
- package/src/shade/playground/foliage_wind/foliage_world.js +593 -0
- package/src/shade/playground/foliage_wind/index.html +254 -0
- package/src/shade/playground/foliage_wind/main.d.ts +2 -0
- package/src/shade/playground/foliage_wind/main.d.ts.map +1 -0
- package/src/shade/playground/foliage_wind/main.js +263 -0
- package/src/shade/playground/tonemap_sdr/README.md +5 -3
- package/src/shade/renderer/Renderer.d.ts +1 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +88 -31
- package/src/shade/renderer/ShadeToneMappingMode.d.ts +3 -2
- package/src/shade/renderer/ShadeToneMappingMode.js +15 -4
- package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +145 -0
- package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts +9 -1
- package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.js +53 -1
- package/src/shade/renderer/animation/ANIMATION_FOLIAGE_JOINT_STRUCT.d.ts +8 -0
- package/src/shade/renderer/animation/ANIMATION_FOLIAGE_JOINT_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/animation/ANIMATION_FOLIAGE_JOINT_STRUCT.js +71 -0
- package/src/shade/renderer/animation/ANIMATION_FOLIAGE_RIG_STRUCT.d.ts +11 -0
- package/src/shade/renderer/animation/ANIMATION_FOLIAGE_RIG_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/animation/ANIMATION_FOLIAGE_RIG_STRUCT.js +32 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts +30 -3
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +532 -79
- package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.d.ts +19 -12
- package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.d.ts.map +1 -1
- package/src/shade/renderer/animation/POSE_ACCUMULATOR_LAYOUT.js +20 -13
- package/src/shade/renderer/animation/ShadeAnimationClip.d.ts +35 -8
- package/src/shade/renderer/animation/ShadeAnimationClip.d.ts.map +1 -1
- package/src/shade/renderer/animation/ShadeAnimationClip.js +433 -2
- package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
- package/src/shade/renderer/animation/chunk_pose_accumulator.js +40 -32
- package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +97 -0
- package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -0
- package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +161 -0
- package/src/shade/renderer/animation/foliage/FoliageWindRig.d.ts +65 -0
- package/src/shade/renderer/animation/foliage/FoliageWindRig.d.ts.map +1 -0
- package/src/shade/renderer/animation/foliage/FoliageWindRig.js +89 -0
- package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts +19 -0
- package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -0
- package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +143 -0
- package/src/shade/renderer/animation/foliage/shader_foliage_wind_apply.d.ts +14 -0
- package/src/shade/renderer/animation/foliage/shader_foliage_wind_apply.d.ts.map +1 -0
- package/src/shade/renderer/animation/foliage/shader_foliage_wind_apply.js +116 -0
- package/src/shade/renderer/animation/pose/pose_evaluate_local.d.ts.map +1 -1
- package/src/shade/renderer/animation/pose/pose_evaluate_local.js +39 -29
- package/src/shade/renderer/animation/shader_animation_pose_resolve.js +37 -37
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +2 -2
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts +38 -0
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/TonemapAces2Tables.js +97 -0
- package/src/shade/renderer/deferred/{TonemapDisplaySettings.d.ts → tonemap/TonemapDisplaySettings.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/TonemapDisplaySettings.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{TonemapDisplaySettings.js → tonemap/TonemapDisplaySettings.js} +5 -5
- package/src/shade/renderer/deferred/{shader_tonemap_HDR.d.ts → tonemap/shader_tonemap_HDR.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR.js → tonemap/shader_tonemap_HDR.js} +9 -9
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts +17 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_aces.js +101 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_none.d.ts → tonemap/shader_tonemap_HDR_none.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_none.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_none.js → tonemap/shader_tonemap_HDR_none.js} +6 -6
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_pbr_neutral.d.ts → tonemap/shader_tonemap_HDR_pbr_neutral.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_pbr_neutral.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_HDR_pbr_neutral.js → tonemap/shader_tonemap_HDR_pbr_neutral.js} +8 -8
- package/src/shade/renderer/deferred/{shader_tonemap_LDR.d.ts → tonemap/shader_tonemap_LDR.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR.js → tonemap/shader_tonemap_LDR.js} +10 -10
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts +10 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.d.ts.map +1 -0
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_aces.js +77 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_none.d.ts → tonemap/shader_tonemap_LDR_none.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_none.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_none.js → tonemap/shader_tonemap_LDR_none.js} +7 -7
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_pbr_neutral.d.ts → tonemap/shader_tonemap_LDR_pbr_neutral.d.ts} +1 -1
- package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_pbr_neutral.d.ts.map +1 -0
- package/src/shade/renderer/deferred/{shader_tonemap_LDR_pbr_neutral.js → tonemap/shader_tonemap_LDR_pbr_neutral.js} +8 -8
- package/src/shade/renderer/extension/RenderExtension.d.ts +7 -0
- package/src/shade/renderer/extension/RenderExtension.d.ts.map +1 -1
- package/src/shade/renderer/extension/RenderExtension.js +9 -0
- package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts +6 -0
- package/src/shade/renderer/extension/RenderExtensionRegistry.d.ts.map +1 -1
- package/src/shade/renderer/extension/RenderExtensionRegistry.js +15 -0
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +10 -3
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascade.js +15 -0
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +8 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +11 -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 +51 -48
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -0
- package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
- package/src/shade/renderer/fluid/mac/FluidMacPasses.js +16 -0
- 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 +15 -3
- 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 +102 -96
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +12 -12
- package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +12 -12
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +8 -1
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +16 -0
- package/src/shade/renderer/fluid/publish/FluidWindPublish.d.ts +7 -0
- package/src/shade/renderer/fluid/publish/FluidWindPublish.d.ts.map +1 -1
- package/src/shade/renderer/fluid/publish/FluidWindPublish.js +10 -0
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/geometry/bvh/GPUBLASRefitBatch.js +2 -2
- package/src/shade/renderer/loader/SceneBundle.d.ts +7 -0
- package/src/shade/renderer/loader/SceneBundle.d.ts.map +1 -1
- package/src/shade/renderer/loader/SceneBundle.js +119 -111
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts +4 -0
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer.js +6 -5
- package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts +8 -7
- package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts.map +1 -1
- package/src/shade/renderer/object_property/chunk_write_object_property_node3d.js +9 -8
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +3 -1
- 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 +9 -4
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- 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 +9 -7
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment.js +15 -7
- package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +6 -4
- package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.js +3 -3
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +8 -5
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +4 -3
- package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +160 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +5 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +15 -5
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/aces2_transform_block.d.ts +41 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/aces2_transform_block.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/aces2_transform_block.js +692 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.d.ts +25 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces2_output_transform.js +446 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts +22 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_aces_ue_matrices.js +68 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts +32 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/aces/chunk_tonemap_ue_filmic.js +163 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts +10 -3
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js +12 -4
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +1 -1
- package/src/shade/renderer/texture/SAMPLER_ANISOTROPIC_CLAMP.d.ts +9 -0
- package/src/shade/renderer/texture/SAMPLER_ANISOTROPIC_CLAMP.d.ts.map +1 -0
- package/src/shade/renderer/texture/SAMPLER_ANISOTROPIC_CLAMP.js +17 -0
- package/src/shade/renderer/texture/SAMPLER_LINEAR_UPSCALE.d.ts +8 -0
- package/src/shade/renderer/texture/SAMPLER_LINEAR_UPSCALE.d.ts.map +1 -1
- package/src/shade/renderer/texture/SAMPLER_LINEAR_UPSCALE.js +28 -20
- package/src/shade/renderer/texture/SAMPLER_TRILINEAR_CLAMP.d.ts +8 -0
- package/src/shade/renderer/texture/SAMPLER_TRILINEAR_CLAMP.d.ts.map +1 -0
- package/src/shade/renderer/texture/SAMPLER_TRILINEAR_CLAMP.js +15 -0
- package/src/shade/renderer/view/chunk_view_mip_bias.d.ts +21 -0
- package/src/shade/renderer/view/chunk_view_mip_bias.d.ts.map +1 -0
- package/src/shade/renderer/view/chunk_view_mip_bias.js +44 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +105 -26
- package/src/engine/graphics/composit/CompositingStages.d.ts +0 -6
- package/src/engine/graphics/composit/CompositingStages.d.ts.map +0 -1
- package/src/engine/graphics/composit/CompositingStages.js +0 -8
- package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.d.ts +0 -7
- package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.d.ts.map +0 -1
- package/src/engine/graphics/geometry/buffered/computeBufferAttributeHash.js +0 -24
- package/src/engine/graphics/geometry/buffered/computeGeometryBoundingSphereMiniball.d.ts +0 -8
- package/src/engine/graphics/geometry/buffered/computeGeometryBoundingSphereMiniball.d.ts.map +0 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryBoundingSphereMiniball.js +0 -17
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.d.ts +0 -8
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.d.ts.map +0 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryEquality.js +0 -60
- package/src/engine/graphics/geometry/buffered/computeGeometryHash.d.ts +0 -7
- package/src/engine/graphics/geometry/buffered/computeGeometryHash.d.ts.map +0 -1
- package/src/engine/graphics/geometry/buffered/computeGeometryHash.js +0 -26
- package/src/engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.d.ts +0 -7
- package/src/engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.d.ts.map +0 -1
- package/src/engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.js +0 -23
- package/src/engine/graphics/geometry/instancing/geometry_copy.d.ts +0 -7
- package/src/engine/graphics/geometry/instancing/geometry_copy.d.ts.map +0 -1
- package/src/engine/graphics/geometry/instancing/geometry_copy.js +0 -15
- package/src/engine/graphics/geometry/instancing/rewriteMaterial.d.ts +0 -2
- package/src/engine/graphics/geometry/instancing/rewriteMaterial.d.ts.map +0 -1
- package/src/engine/graphics/geometry/instancing/rewriteMaterial.js +0 -57
- package/src/engine/graphics/geometry/ribbon/Quad.d.ts +0 -96
- package/src/engine/graphics/geometry/ribbon/Quad.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/Quad.js +0 -213
- package/src/engine/graphics/geometry/ribbon/copyAttributeV3.d.ts +0 -9
- package/src/engine/graphics/geometry/ribbon/copyAttributeV3.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/copyAttributeV3.js +0 -12
- package/src/engine/graphics/geometry/ribbon/copyAttributeValue.d.ts +0 -10
- package/src/engine/graphics/geometry/ribbon/copyAttributeValue.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/copyAttributeValue.js +0 -17
- package/src/engine/graphics/geometry/ribbon/equalAttributeV3.d.ts +0 -10
- package/src/engine/graphics/geometry/ribbon/equalAttributeV3.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/equalAttributeV3.js +0 -13
- package/src/engine/graphics/geometry/ribbon/equalAttributeValue.d.ts +0 -11
- package/src/engine/graphics/geometry/ribbon/equalAttributeValue.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/equalAttributeValue.js +0 -24
- package/src/engine/graphics/geometry/ribbon/rotateRibbon.d.ts +0 -6
- package/src/engine/graphics/geometry/ribbon/rotateRibbon.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/rotateRibbon.js +0 -37
- package/src/engine/graphics/geometry/ribbon/updateTipPosition.d.ts +0 -9
- package/src/engine/graphics/geometry/ribbon/updateTipPosition.d.ts.map +0 -1
- package/src/engine/graphics/geometry/ribbon/updateTipPosition.js +0 -52
- package/src/engine/graphics/geometry/skining/computeSkinnedMeshVertices.d.ts +0 -8
- package/src/engine/graphics/geometry/skining/computeSkinnedMeshVertices.d.ts.map +0 -1
- package/src/engine/graphics/geometry/skining/computeSkinnedMeshVertices.js +0 -54
- package/src/engine/graphics/render/RenderPassType.d.ts +0 -6
- package/src/engine/graphics/render/RenderPassType.d.ts.map +0 -1
- package/src/engine/graphics/render/RenderPassType.js +0 -8
- package/src/engine/graphics/render/layers/RenderLayer.d.ts +0 -78
- package/src/engine/graphics/render/layers/RenderLayer.d.ts.map +0 -1
- package/src/engine/graphics/render/layers/RenderLayer.js +0 -95
- package/src/engine/graphics/render/layers/RenderLayerManager.d.ts +0 -72
- package/src/engine/graphics/render/layers/RenderLayerManager.d.ts.map +0 -1
- package/src/engine/graphics/render/layers/RenderLayerManager.js +0 -160
- package/src/engine/graphics/render/layers/RenderLayerManagerState.d.ts +0 -18
- package/src/engine/graphics/render/layers/RenderLayerManagerState.d.ts.map +0 -1
- package/src/engine/graphics/render/layers/RenderLayerManagerState.js +0 -48
- package/src/engine/graphics/render/layers/RenderLayerState.d.ts +0 -18
- package/src/engine/graphics/render/layers/RenderLayerState.d.ts.map +0 -1
- package/src/engine/graphics/render/layers/RenderLayerState.js +0 -27
- package/src/engine/graphics/render/layers/RenderLayerUtils.d.ts +0 -8
- package/src/engine/graphics/render/layers/RenderLayerUtils.d.ts.map +0 -1
- package/src/engine/graphics/render/layers/RenderLayerUtils.js +0 -103
- package/src/engine/graphics/render/make_bvh_visibility_builder.d.ts +0 -10
- package/src/engine/graphics/render/make_bvh_visibility_builder.d.ts.map +0 -1
- package/src/engine/graphics/render/make_bvh_visibility_builder.js +0 -64
- package/src/engine/graphics/render/view/CameraViewFlags.d.ts +0 -7
- package/src/engine/graphics/render/view/CameraViewFlags.d.ts.map +0 -1
- package/src/engine/graphics/render/view/CameraViewFlags.js +0 -9
- package/src/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +0 -143
- package/src/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts.map +0 -1
- package/src/engine/graphics/render/visibility/IncrementalDeltaSet.js +0 -328
- package/src/engine/graphics/render/visibility/VisibilityComputer.d.ts +0 -39
- package/src/engine/graphics/render/visibility/VisibilityComputer.d.ts.map +0 -1
- package/src/engine/graphics/render/visibility/VisibilityComputer.js +0 -80
- package/src/engine/graphics/render/visibility/VisibilityFilter.d.ts +0 -29
- package/src/engine/graphics/render/visibility/VisibilityFilter.d.ts.map +0 -1
- package/src/engine/graphics/render/visibility/VisibilityFilter.js +0 -37
- package/src/engine/graphics3/animation/write_graph_playback.d.ts +0 -24
- package/src/engine/graphics3/animation/write_graph_playback.d.ts.map +0 -1
- package/src/engine/graphics3/animation/write_graph_playback.js +0 -48
- package/src/shade/renderer/deferred/TonemapDisplaySettings.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR_none.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR_none.d.ts.map +0 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.d.ts.map +0 -1
|
@@ -3,12 +3,12 @@ import { lerp } from "../../../../core/math/lerp.js";
|
|
|
3
3
|
import { scs3d_sample_linear } from "../../../graphics/texture/3d/scs3d_sample_linear.js";
|
|
4
4
|
|
|
5
5
|
// Voxel grid is finer than the spacing hint so it resolves sub-`minSpacing` features (thin corridors).
|
|
6
|
-
|
|
6
|
+
const DEFAULT_OVERSAMPLE = 2;
|
|
7
7
|
// Per-axis voxel resolution is capped so the SDF grid stays bounded (256³ f32 ≈ 64 MB).
|
|
8
|
-
|
|
8
|
+
const DEFAULT_RESOLUTION_LIMIT = 256;
|
|
9
9
|
// Open halls get probes at most this multiple of `minSpacing` apart (the sparseness ceiling + the SDF query
|
|
10
10
|
// cutoff — beyond it "very open" is good enough).
|
|
11
|
-
|
|
11
|
+
const DEFAULT_SPARSENESS_RATIO = 4;
|
|
12
12
|
|
|
13
13
|
const ASCENT_ITERATIONS = 5;
|
|
14
14
|
const ASCENT_RATE = 0.2;
|
|
@@ -31,16 +31,28 @@ const ASCENT_RATE = 0.2;
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Build a signed distance field on a voxel grid over `bounds` by sampling
|
|
34
|
-
* {@link AcousticOccluderIndex#signedDistanceAt}. The grid is finer than `minSpacing` (by
|
|
35
|
-
* so it resolves sub-spacing features, and capped at
|
|
34
|
+
* {@link AcousticOccluderIndex#signedDistanceAt}. The grid is finer than `minSpacing` (by `oversample`,
|
|
35
|
+
* default {@link DEFAULT_OVERSAMPLE}) so it resolves sub-spacing features, and capped at `resolutionLimit`³
|
|
36
|
+
* (default {@link DEFAULT_RESOLUTION_LIMIT}³).
|
|
36
37
|
*
|
|
37
|
-
* @param {
|
|
38
|
-
* @param {
|
|
39
|
-
* @param {number}
|
|
40
|
-
* @param {number}
|
|
38
|
+
* @param {Object} options
|
|
39
|
+
* @param {AcousticOccluderIndex} options.index the acoustic scene
|
|
40
|
+
* @param {number[]} options.bounds `[x0,y0,z0,x1,y1,z1]`
|
|
41
|
+
* @param {number} options.minSpacing the probe spacing hint
|
|
42
|
+
* @param {number} [options.sparsenessRatio]
|
|
43
|
+
* @param {number} [options.oversample]
|
|
44
|
+
* @param {number} [options.resolutionLimit]
|
|
41
45
|
* @returns {SdfGrid}
|
|
42
46
|
*/
|
|
43
|
-
export function build_sdf_grid(
|
|
47
|
+
export function build_sdf_grid({
|
|
48
|
+
index,
|
|
49
|
+
bounds,
|
|
50
|
+
minSpacing,
|
|
51
|
+
sparsenessRatio = DEFAULT_SPARSENESS_RATIO,
|
|
52
|
+
oversample = DEFAULT_OVERSAMPLE,
|
|
53
|
+
resolutionLimit = DEFAULT_RESOLUTION_LIMIT,
|
|
54
|
+
}) {
|
|
55
|
+
|
|
44
56
|
const maxSpacing = minSpacing * sparsenessRatio;
|
|
45
57
|
|
|
46
58
|
const x0 = bounds[0], y0 = bounds[1], z0 = bounds[2];
|
|
@@ -48,10 +60,10 @@ export function build_sdf_grid(index, bounds, minSpacing, sparsenessRatio = DEFA
|
|
|
48
60
|
|
|
49
61
|
const extX = x1 - x0, extY = y1 - y0, extZ = z1 - z0;
|
|
50
62
|
|
|
51
|
-
const voxel = minSpacing /
|
|
52
|
-
const rx = clamp(Math.ceil(extX / voxel) + 1, 2,
|
|
53
|
-
const ry = clamp(Math.ceil(extY / voxel) + 1, 2,
|
|
54
|
-
const rz = clamp(Math.ceil(extZ / voxel) + 1, 2,
|
|
63
|
+
const voxel = minSpacing / oversample;
|
|
64
|
+
const rx = clamp(Math.ceil(extX / voxel) + 1, 2, resolutionLimit);
|
|
65
|
+
const ry = clamp(Math.ceil(extY / voxel) + 1, 2, resolutionLimit);
|
|
66
|
+
const rz = clamp(Math.ceil(extZ / voxel) + 1, 2, resolutionLimit);
|
|
55
67
|
|
|
56
68
|
// actual per-axis voxel size (probe positions lerp over [0, res-1])
|
|
57
69
|
const vsX = extX / (rx - 1);
|
|
@@ -76,7 +88,7 @@ export function build_sdf_grid(index, bounds, minSpacing, sparsenessRatio = DEFA
|
|
|
76
88
|
// "open air" = off any surface by ~½ a NOMINAL voxel. Based on the spacing hint, NOT the actual per-axis
|
|
77
89
|
// voxel size: a degenerate (zero-extent) axis can't zero it, and the resolution cap can't inflate it past
|
|
78
90
|
// maxSpacing (which would reject every voxel).
|
|
79
|
-
const clearanceFloor = (minSpacing /
|
|
91
|
+
const clearanceFloor = (minSpacing / oversample) * 0.5;
|
|
80
92
|
|
|
81
93
|
return {
|
|
82
94
|
sdf, rx, ry, rz, strideZ, total,
|
|
@@ -86,14 +98,31 @@ export function build_sdf_grid(index, bounds, minSpacing, sparsenessRatio = DEFA
|
|
|
86
98
|
};
|
|
87
99
|
}
|
|
88
100
|
|
|
89
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* World position of the (fractional) voxel coordinate `(fx,fy,fz)`, written into `out`.
|
|
103
|
+
*
|
|
104
|
+
* @param {SdfGrid} grid
|
|
105
|
+
* @param {number[]|Float32Array} out `[x,y,z]` written here
|
|
106
|
+
* @param {number} fx
|
|
107
|
+
* @param {number} fy
|
|
108
|
+
* @param {number} fz
|
|
109
|
+
* @returns {void}
|
|
110
|
+
*/
|
|
90
111
|
export function grid_voxel_to_world(grid, out, fx, fy, fz) {
|
|
91
112
|
out[0] = grid.x0 + fx * grid.vsX;
|
|
92
113
|
out[1] = grid.y0 + fy * grid.vsY;
|
|
93
114
|
out[2] = grid.z0 + fz * grid.vsZ;
|
|
94
115
|
}
|
|
95
116
|
|
|
96
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* SDF at a WORLD position via trilinear interpolation of the grid (edge-clamped).
|
|
119
|
+
*
|
|
120
|
+
* @param {SdfGrid} grid
|
|
121
|
+
* @param {number} x
|
|
122
|
+
* @param {number} y
|
|
123
|
+
* @param {number} z
|
|
124
|
+
* @returns {number}
|
|
125
|
+
*/
|
|
97
126
|
export function grid_sample_world(grid, x, y, z) {
|
|
98
127
|
const fx = grid.vsX > 0 ? (x - grid.x0) / grid.vsX : 0;
|
|
99
128
|
const fy = grid.vsY > 0 ? (y - grid.y0) / grid.vsY : 0;
|
|
@@ -108,6 +137,12 @@ export function grid_sample_world(grid, x, y, z) {
|
|
|
108
137
|
* {@link scs3d_sample_linear} samples — so the interpolation is delegated rather than re-derived here.
|
|
109
138
|
* (Same clamp semantics: clamping the COORDINATE into `[0, res-1]` and clamping the two sample INDICES
|
|
110
139
|
* agree on every input, including out-of-range coordinates, where both collapse to the edge voxel.)
|
|
140
|
+
*
|
|
141
|
+
* @param {SdfGrid} grid
|
|
142
|
+
* @param {number} x
|
|
143
|
+
* @param {number} y
|
|
144
|
+
* @param {number} z
|
|
145
|
+
* @returns {number}
|
|
111
146
|
*/
|
|
112
147
|
export function grid_sample_trilinear(grid, x, y, z) {
|
|
113
148
|
return scs3d_sample_linear(grid.sdf, grid.rx, grid.ry, grid.rz, x, y, z);
|
|
@@ -117,6 +152,13 @@ export function grid_sample_trilinear(grid, x, y, z) {
|
|
|
117
152
|
* Gradient-ascend a voxel to the local SDF maximum (the most-open sub-voxel point), written into `out` as a
|
|
118
153
|
* fractional voxel coordinate clamped to within ½ voxel of the start. Central-difference gradient on the
|
|
119
154
|
* trilinearly-sampled SDF; the gradient is not normalised, so steps shrink near the maximum.
|
|
155
|
+
*
|
|
156
|
+
* @param {number[]|Float32Array} out `[fx,fy,fz]` written here
|
|
157
|
+
* @param {SdfGrid} grid
|
|
158
|
+
* @param {number} vx
|
|
159
|
+
* @param {number} vy
|
|
160
|
+
* @param {number} vz
|
|
161
|
+
* @returns {void}
|
|
120
162
|
*/
|
|
121
163
|
export function grid_local_maximum(out, grid, vx, vy, vz) {
|
|
122
164
|
const minX = vx - 0.4999, maxX = vx + 0.4999;
|
|
@@ -144,6 +186,14 @@ export function grid_local_maximum(out, grid, vx, vy, vz) {
|
|
|
144
186
|
/**
|
|
145
187
|
* Mark every voxel whose centre is within `radius` of the world point `(px,py,pz)` as claimed. O((radius/voxel)³)
|
|
146
188
|
* per call. A degenerate axis (`vs===0`, a zero-extent bake region) claims all its coincident layers.
|
|
189
|
+
*
|
|
190
|
+
* @param {Uint8Array} claimed per-voxel claimed flags (`total` elements)
|
|
191
|
+
* @param {SdfGrid} grid
|
|
192
|
+
* @param {number} px
|
|
193
|
+
* @param {number} py
|
|
194
|
+
* @param {number} pz
|
|
195
|
+
* @param {number} radius
|
|
196
|
+
* @returns {void}
|
|
147
197
|
*/
|
|
148
198
|
export function grid_claim_sphere(claimed, grid, px, py, pz, radius) {
|
|
149
199
|
const { rx, ry, rz, strideZ, x0, y0, z0, vsX, vsY, vsZ } = grid;
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Meep Procedural Foliage & Tree Generation System — Architecture & Design Document
|
|
2
|
+
|
|
3
|
+
## 1. Executive Summary & Architectural Philosophy
|
|
4
|
+
|
|
5
|
+
This document specifies a production-grade, State-of-the-Art (SotA) procedural tree and foliage generation system for **Meep Engine** (`src/generation/foliage/`), comparable in capability to SpeedTree while engineered from the ground up around Meep's data-oriented, zero-allocation primitives and visibility-buffer (`MeshletGeometry` / `StandardShadeMaterial` / `Prefab`) rendering architecture.
|
|
6
|
+
|
|
7
|
+
### Core Design Tenets
|
|
8
|
+
1. **Turn-Key Top Layer, Layered Override API Underneath**:
|
|
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`, `BranchLevelConfig`, `CrownConfig`, `FoliageConfig`, `BarkMaterialConfig`, `FoliageMaterialConfig`, and `TreeWindConfig` with `AnimationCurve` profiles and full JSON serialization.
|
|
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
|
+
2. **Zero Duplicate Adjacent Infrastructure**:
|
|
13
|
+
- **Coordinate System**: Strictly Meep's right-handed **Y-up** convention (`Vector3.up = (0, 1, 0)`, ground plane `X-Z`).
|
|
14
|
+
- **Splines & Profiles**: 3D branch spines are piecewise **Cubic Hermite** segments evaluated via `spline3_hermite` and `spline3_hermite_derivative`. 1D distribution profiles (radius taper modifier, child length scaling, insertion angle, internode density) use Meep's `AnimationCurve` and `Keyframe` (`src/engine/animation/curve/AnimationCurve.js`).
|
|
15
|
+
- **Topological Skeleton (`Graph` + `Transform64` + `Attribute`)**: The hierarchical branch graph is stored directly in Meep's directed **`Graph`** (`src/core/graph/v2/Graph.js`, using `EdgeDirectionType.Forward` edges from `src/core/graph/Edge.js`), while each node's 3D position, Rotation-Minimizing Frame (`[R, S, T]`), and cross-sectional radius are stored in **`Transform64`** (`src/engine/ecs/transform/Transform64.js`), and per-node / per-segment attributes are packed into **`Attribute`** buffers (`src/shade/renderer/geometry/Attribute.js`). (`BinaryTopology` is a polygonal surface mesh structure with unordered edge vertices and is not contorted into a directed graph.)
|
|
16
|
+
- **Spatial Acceleration**: Crown competition and space colonization use **`PointHashGrid3`** (`src/core/geom/3d/hash-grid/PointHashGrid3.js`) for zero-allocation $O(N)$ neighborhood queries.
|
|
17
|
+
- **Math, Noise, & Determinism**: Uses `v3_*`, `quat3_*`, `m4_*`, `aabb3_*`, `tube_frame_transport`, `sdnoise3_array`, `curl_noise_3d`, `seededRandom`, `hash_mix2`, and `hash_mix3`.
|
|
18
|
+
- **Real-Time Rendering Native to Shade**: Emits `Geometry` and `MeshletGeometry` (`meshlet_geometry_build_from_geometry`), `StandardShadeMaterial` (with procedural `Sampler2D` $\to$ `ShadeImage` $\to$ `ShadeTexture` albedo/normal/ORM synthesis when custom textures are omitted), skeletal `Skin` bindings (`StandardAttributes.SkinningJoints` + `StandardAttributes.SkinningWeights`), GPU fluid-driven `FoliageWindRig`s (`shader_foliage_wind_apply` sampling `GPUSceneWind`), `SceneBundle`s, and compiled `Prefab`s (`prefab_compile`).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. System Architecture & Pipeline Overview
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ TOP-LEVEL TURN-KEY API │
|
|
27
|
+
│ generate_tree(options) / build_tree_prefab(options) / place_tree(...) │
|
|
28
|
+
│ Presets: Oak, Pine, Birch, Willow, Maple, Spruce, Palm, Shrub, Fern │
|
|
29
|
+
└──────────────────────────────────────┬──────────────────────────────────────┘
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
33
|
+
│ STAGE 1: SKELETON TOPOLOGY & HYBRID GROWTH (Graph + Transform64 + Attribute)│
|
|
34
|
+
│ • Parametric Allometric Growth (Weber & Penn levels 0..L_max) │
|
|
35
|
+
│ • Crown Envelope SDFs + Space Colonization (PointHashGrid3) │
|
|
36
|
+
│ • Tropisms (Gravitropism, Phototropism/Heliotropism, Curl/Simplex Gnarl) │
|
|
37
|
+
│ • Dichotomous/Sympodial Trunk Splitting & Apical Dominance │
|
|
38
|
+
│ • Da Vinci / Murray Pipe-Model Cross-Section Accumulation (r_p^α = Σ r_i^α)│
|
|
39
|
+
│ • Rotation-Minimizing Frames (RMF: Double-Reflection + tube_frame_transport)│
|
|
40
|
+
└──────────────────────────────────────┬──────────────────────────────────────┘
|
|
41
|
+
│
|
|
42
|
+
┌─────────────────┴─────────────────┐
|
|
43
|
+
▼ ▼
|
|
44
|
+
┌─────────────────────────────────────────┐ ┌─────────────────────────────────┐
|
|
45
|
+
│ STAGE 2A: BARK & BRANCH MESH SYNTHESIS │ │ STAGE 2B: PHYLLOTAXIS & FOLIAGE │
|
|
46
|
+
│ • Hermite Spine Sampling (spline3_*) │ │ • Phyllotactic Node Placement │
|
|
47
|
+
│ • Root Buttressing & Multi-Lobe Flare │ │ (Golden Angle 137.5°, │
|
|
48
|
+
│ • Bark Flutes & Knot Swelling │ │ Decussate, Opposite, Whorl) │
|
|
49
|
+
│ • Seamless Branch Welding / Collars │ │ • Heliotropic & Gravitropic │
|
|
50
|
+
│ (Ray-Cylinder Snap + Normal Slerp) │ │ Petiole Orientation │
|
|
51
|
+
│ • Adaptive Ring Collapse (Watertight) │ │ • Folded V-Cards, Cross-Cards, │
|
|
52
|
+
│ • Quantized Seamless Bark UVs │ │ Alpha-Tight Hulls, & Fronds │
|
|
53
|
+
└────────────────────┬────────────────────┘ └────────────────┬────────────────┘
|
|
54
|
+
└─────────────────┬─────────────────────┘
|
|
55
|
+
▼
|
|
56
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
57
|
+
│ STAGE 3: REAL-TIME SHADING, FLUID WIND SKINNING, & MULTI-LOD COMPILATION │
|
|
58
|
+
│ • Analytic Canopy AO + Spherized/Puffed Foliage Normals │
|
|
59
|
+
│ • Skeletal Joint Extraction (Skin) & Per-Vertex Joint/Weight Binding │
|
|
60
|
+
│ • GPU Fluid-Driven Foliage Bone Rig (FoliageWindRig + GPUSceneWind) │
|
|
61
|
+
│ • Multi-LOD Chain (LOD0..LOD3) with Area-Compensated Card Decimation │
|
|
62
|
+
│ • Procedural PBR Texture & StandardShadeMaterial Synthesis │
|
|
63
|
+
│ • MeshletGeometry, SceneBundle, & Prefab Compilation │
|
|
64
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3. Core Engine Primitives Leveraged (`Graph`, `Transform64`, `Attribute`)
|
|
70
|
+
|
|
71
|
+
Rather than contorting `BinaryTopology` (which is a Blender BMesh-style polygonal surface mesh structure with unordered edge endpoints) into a directed graph, the foliage system builds directly on Meep's dedicated graph, transform, and attribute classes:
|
|
72
|
+
|
|
73
|
+
1. **`Graph` & `Edge` (`src/core/graph/v2/Graph.js`, `src/core/graph/Edge.js`)**:
|
|
74
|
+
- Represents the directed skeletal topology of the tree (`EdgeDirectionType.Forward` edges `parent_v -> child_v`), connecting both intra-branch Cubic Hermite spine segments and inter-branch lateral attachments into a single rooted arborescence.
|
|
75
|
+
2. **`Transform64` & `t64_look_rotation` (`src/engine/ecs/transform/Transform64.js`, `t64_look_rotation.js`)**:
|
|
76
|
+
- Stores each skeleton node's and each foliage attachment's 3D position (`translation` at offset `12`), orthonormal Rotation-Minimizing Frame (`rotation` quaternion at offset `16` mapping local $+X \to \mathbf{R}_v$, $+Y \to \mathbf{S}_v$, $+Z \to \mathbf{T}_v$), and cross-sectional radius (`scale` at offset `20`) in a single contiguous 23-float64 buffer.
|
|
77
|
+
3. **`Attribute` (`src/shade/renderer/geometry/Attribute.js`)**:
|
|
78
|
+
- Stores typed-array per-node, per-segment, and per-attachment channels (`Attribute.from(typedArray, itemSize, name)`) with `AttributeSpec` metadata, versioning, hashing, and deep cloning.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 4. Stage 1: Skeleton Topology & Hybrid Growth Engine
|
|
83
|
+
|
|
84
|
+
### 4.1 `TreeSkeleton` Layout on `Graph`, `Transform64`, and `Attribute`
|
|
85
|
+
A `TreeSkeleton` combines a `Graph<number>` (`skeleton.graph`), an array of `Transform64` node frames (`skeleton.node_transforms`), and typed `Attribute` buffers:
|
|
86
|
+
|
|
87
|
+
#### Node Transforms & Node `Attribute`s (Skeleton Nodes)
|
|
88
|
+
- **`node_transforms[v]: Transform64`**:
|
|
89
|
+
- `translation` (`f64[3]` at offset 12): Node 3D position $\mathbf{p}_v = (x, y, z)$ with $+Y$ up.
|
|
90
|
+
- `rotation` (`f64[4]` at offset 16): Unit quaternion orienting local $+X$ (`right`) along RMF radial vector $\mathbf{R}_v$, local $+Y$ (`up`) along binormal $\mathbf{S}_v = \mathbf{T}_v \times \mathbf{R}_v$, and local $+Z$ (`forward`) along unit spine tangent $\mathbf{T}_v$.
|
|
91
|
+
- `scale` (`f64[3]` at offset 20): Uniform cross-sectional radius $R_v$ at node $v$.
|
|
92
|
+
- **Per-Node `Attribute`s**:
|
|
93
|
+
- `attr_node_branch_info` (`Int32Array`, `itemSize = 4`): `[branch_id, level, parent_branch_id, in_segment_id]`.
|
|
94
|
+
- `attr_node_spine_param` (`Float32Array`, `itemSize = 3`): `[t_normalized, arc_length_s, phase_hash]` where $t \in [0, 1]$ is position along the current branch spine, $s$ is cumulative arc length from branch base, and `phase_hash` $\in [0, 1]$ is the deterministic wind phase.
|
|
95
|
+
- `attr_node_joint` (`Uint16Array`, `itemSize = 2`): `[skin_joint_index, parent_skin_joint_index]` for skeletal wind skinning.
|
|
96
|
+
|
|
97
|
+
#### Segment `Attribute`s (Cubic Hermite Spine Segments)
|
|
98
|
+
Each Cubic Hermite spine segment $e = (v_0 \to v_1)$ adds a directed `EdgeDirectionType.Forward` edge in `skeleton.graph` and stores:
|
|
99
|
+
- `attr_segment_endpoints` (`Int32Array`, `itemSize = 2`): `[v0, v1]`.
|
|
100
|
+
- `attr_segment_hermite_m0` (`Float32Array`, `itemSize = 3`): Exit tangent vector $\mathbf{m}_0$ at $v_0$ (scaled by chord length $\|\mathbf{p}_{v_1} - \mathbf{p}_{v_0}\|$).
|
|
101
|
+
- `attr_segment_hermite_m1` (`Float32Array`, `itemSize = 3`): Entry tangent vector $\mathbf{m}_1$ at $v_1$ (scaled by chord length).
|
|
102
|
+
- `attr_segment_metrics` (`Float32Array`, `itemSize = 2`): `[segment_length, parent_attach_t]`.
|
|
103
|
+
|
|
104
|
+
Evaluating any point or derivative at local parameter $u \in [0, 1]$ along edge $e$ directly invokes:
|
|
105
|
+
- `spline3_hermite(u, p0x, p1x, m0x, m1x)` (for $x, y, z$)
|
|
106
|
+
- `spline3_hermite_derivative(u, p0x, p1x, m0x, m1x)` (for $x, y, z$)
|
|
107
|
+
|
|
108
|
+
### 4.2 Hybrid Parametric + Space-Colonization Growth Algorithm
|
|
109
|
+
For each recursion level $l \in \{0, \dots, L_{\max}\}$:
|
|
110
|
+
1. **Crown Envelope & Space Colonization Field**:
|
|
111
|
+
- 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
|
+
- 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
|
+
2. **Branch Spawn & Phyllotactic Budding**:
|
|
114
|
+
- Along each parent branch of level $l - 1$, child branches are spawned above `bare_length_ratio` $t_{\text{bare}} \in [0, 1)$ according to the level's `PhyllotaxisMode` (`SpiralGolden` $137.507764^\circ$, `AlternateDistichous` $180^\circ$, `OppositeDecussate` $180^\circ + 90^\circ$ flip, `Opposite` $180^\circ$, `Whorled` $360^\circ / M$).
|
|
115
|
+
- Child branch length $L_l(t_p)$ is modulated by the parent's `length_profile: AnimationCurve` and the crown envelope $S_{\text{env}}(h_{\text{norm}})$.
|
|
116
|
+
- 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
|
+
- The child's initial RMF normal $\mathbf{R}_c(0)$ is aligned with the adaxial (upper crotch) projection of $\mathbf{T}_p$:
|
|
118
|
+
$$\mathbf{R}_c(0) = \text{normalize}\big(\mathbf{T}_p - (\mathbf{T}_p \cdot \mathbf{T}_c(0))\mathbf{T}_c(0)\big)$$
|
|
119
|
+
guaranteeing that $\theta = 0$ on the child's cross-section always lies at the top of the branch collar.
|
|
120
|
+
3. **Stepped Spine Integration with Tropisms, Gnarl, & Splits**:
|
|
121
|
+
- As segment $k \to k+1$ advances by $\Delta s = L_l / N_{\text{seg}}$:
|
|
122
|
+
- **Intrinsic curvature**: Pitch rotation around $\mathbf{S}_k$ by $\Delta \theta_{\text{curve}}(t_k)$ and helical twist around $\mathbf{T}_k$.
|
|
123
|
+
- **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
|
+
- **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
|
+
- **Curl / Simplex Gnarl**: 3D divergence-free `curl_noise_3d` (or `sdnoise3_array`) projected perpendicular to $\mathbf{T}_k$.
|
|
126
|
+
- **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
|
+
- **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
|
+
- **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`.
|
|
129
|
+
4. **Bottom-Up Pipe-Model Cross-Section Accumulation**:
|
|
130
|
+
- 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
|
+
$$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
|
+
- 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]$.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 5. Stage 2A: Bark & Branch Mesh Synthesis
|
|
137
|
+
|
|
138
|
+
### 5.1 Root Flare, Buttressing, & Fluted Cross-Sections
|
|
139
|
+
At longitudinal spline parameter $t \in [0, 1]$ (arc-length $s$) and cross-sectional azimuth $\theta \in [0, 2\pi)$:
|
|
140
|
+
$$R(t, \theta) = R_{\text{node}}(t) \cdot \Big[ 1 + A_{\text{flare}}(1 - \text{smoothstep}(0, t_{\text{flare}}, t))^{p_{\text{flare}}} \Psi_{\text{lobes}}(\theta, t) + A_{\text{flute}} \sin(k_{\text{flute}}\theta + \omega_{\text{twist}} s) \Big]$$
|
|
141
|
+
where $\Psi_{\text{lobes}}(\theta, t) = \sum_{m=1}^{N_{\text{lobes}}} w_m \max(0, \cos(\theta - \phi_m - \omega_{\text{twist}} t))^{s_{\text{lobe}}}$ creates realistic root buttresses at the base of the trunk ($l = 0$).
|
|
142
|
+
|
|
143
|
+
### 5.2 Seamless Branch Welding (Collar Blending)
|
|
144
|
+
For any lateral branch ($l \ge 1$) attached to a parent branch of radius $R_p$ at point $\mathbf{x}_p$ with parent axis $\mathbf{T}_p$:
|
|
145
|
+
1. **Collar Ring Projection onto Parent Cylinder**:
|
|
146
|
+
- For the first $K_{\text{weld}}$ rings ($u = k / K_{\text{weld}} \in [0, 1]$), the base collar radius is flared by `collar_spread_upper` (crotch side $\theta \approx 0$) and `collar_spread_lower` (underside $\theta \approx \pi$).
|
|
147
|
+
- Each base vertex ($u = 0$) is projected backward along $-\mathbf{T}_{c,0}$ onto the parent branch cylinder surface of radius $R_p$ around axis $\mathbf{T}_p$ (clamped cleanly to $\le 0.92 R_p$ radial offset so wide child branches never miss the parent cylinder).
|
|
148
|
+
- Intermediate collar rings ($0 < u < 1$) blend via Hermite weight $(1 - u)^2$ between the parent-conforming collar curve and the cylindrical child branch tube.
|
|
149
|
+
2. **Normal Blending ($C^1$ Shading Continuity)**:
|
|
150
|
+
- At $u = 0$, the vertex normal is set to the parent cylinder's outward radial normal $\mathbf{n}_{\text{parent}}$ at the contact point.
|
|
151
|
+
- Across $u \in [0, 1]$, the vertex normal is interpolated via spherical/normalized linear blend between $\mathbf{n}_{\text{parent}}$ and the child's analytic tapered tube normal $\mathbf{n}_{\text{child}}$.
|
|
152
|
+
|
|
153
|
+
### 5.3 Watertight Adaptive Radial & Longitudinal Tessellation
|
|
154
|
+
- Ring radial vertex count $M_i$ adapts to local radius $R(t_i)$ and target LOD scale:
|
|
155
|
+
$$M_i = \text{clamp}\!\left( \lceil 2\pi R(t_i) / \epsilon_{\text{radial}} \rceil, \, M_{\min}, \, M_{\max} \right)$$
|
|
156
|
+
- Whenever $M_{i+1} < M_i$ between consecutive rings $i$ and $i+1$, a **manifold zippering strip** advances around $\theta \in [0, 2\pi]$ on whichever ring has the smaller next normalized angle $j / M$, emitting $M_i + M_{i+1}$ triangles with **zero T-junctions** and preserving UV seam duplication at $\theta = 0$ and $\theta = 2\pi$.
|
|
157
|
+
- Branch tips are closed with either a tapered apex fan (when $R_{\text{tip}} \le \epsilon$) or a rounded cap.
|
|
158
|
+
|
|
159
|
+
### 5.4 Quantized Seamless Bark UVs
|
|
160
|
+
- At each branch base, circumferential tile count is quantized to an integer:
|
|
161
|
+
$$K_{\text{wrap}} = \max\!\left(1, \, \text{round}(2\pi R_0 \cdot \rho_{\text{tex}})\right)$$
|
|
162
|
+
- Vertex $j \in \{0, \dots, M_i\}$ receives $U_{i,j} = K_{\text{wrap}} \cdot (j / M_i) + \tau_{\text{twist}} s_i$, ensuring $U_{i,M_i} - U_{i,0} = K_{\text{wrap}} \in \mathbb{Z}$ (zero vertical texture seam) and $V_i = s_i \cdot \rho_{\text{tex}}$.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 6. Stage 2B: Botanical Phyllotaxis & Foliage Synthesis
|
|
167
|
+
|
|
168
|
+
### 6.1 Phyllotactic Attachment Generator
|
|
169
|
+
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), plus terminal rosette clustering at branch tips ($t \to 1$).
|
|
171
|
+
- **Heliotropic & Gravitropic Orientation**:
|
|
172
|
+
- 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
|
+
|
|
174
|
+
### 6.2 Foliage Topologies
|
|
175
|
+
Supports 5 production real-time foliage card/mesh archetypes:
|
|
176
|
+
1. **`FoldedVCard` (Default Broadleaf Cluster)**: $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.
|
|
177
|
+
2. **`CrossCard` (Conifer Needle Tuft / Dense Shrub Cluster)**: Two orthogonal intersecting V-cards rotated by $90^\circ$ around the petiole axis $\mathbf{F}$.
|
|
178
|
+
3. **`TriStarCluster` (Volumetric Bush / Pine Shoot)**: Three cards arranged at $60^\circ$ star angles with radial offset.
|
|
179
|
+
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. **`OctagonalCutoutHull` (Tight Alpha-Bound Card)**: 6-vertex diamond/hexagonal hull trimming empty corner texels to cut alpha-test quad overdraw by ~35%.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 7. Stage 3: Shading, Wind Rigging, Materials, & Multi-LODs
|
|
185
|
+
|
|
186
|
+
### 7.1 Canopy Ambient Occlusion & Spherized Foliage Normals
|
|
187
|
+
- **Per-Vertex Canopy AO (`StandardAttributes.Color`)**:
|
|
188
|
+
- 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
|
+
- 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.
|
|
190
|
+
- **Spherized / Puffed Foliage Normals (`StandardAttributes.Normal`)**:
|
|
191
|
+
- 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
|
+
|
|
193
|
+
### 7.2 Real-Time Wind Encoding & GPU Fluid-Driven Foliage Bone Animation
|
|
194
|
+
Meep's visibility-buffer renderer (`Shade`) deforms `MeshletGeometry` on the GPU via Remedy / *Alan Wake 2*-style dual-quaternion compute skinning (`GPUAnimationManager` + `GPUMeshSkinningContext`) and publishes a unified 3D fluid dynamics wind field (`GPUSceneWind`, combining `GlobalFluidEffector` far-field wind + gusts and the 3D MAC `GPUFluidCascadeStack` local wakes, vortices, and explosions) samplable on the GPU via `chunk_wind_field_sample` (`wind_field_sample(pos_ws)`). Rather than shipping baked keyframe animation clips, foliage bones are driven directly on the GPU by the fluid dynamics wind field:
|
|
195
|
+
1. **`uv1` Wind Weight Packing (`StandardAttributes.TextureCoordinates1`)**:
|
|
196
|
+
- Every bark and foliage vertex writes normalized `uv1 = [wind_hierarchy_weight, wind_edge_flutter_weight]` in $[0, 1]^2$ (encoded losslessly to `u16x2` in `MeshletBatch`).
|
|
197
|
+
2. **Skeletal Joint Hierarchy & `Skin` Generation**:
|
|
198
|
+
- The tree generator maps structural nodes (trunk sections + primary boughs up to a configurable joint budget $J_{\max} \le 64$) to `SceneNode` joints in pre-order.
|
|
199
|
+
- Every bark and foliage vertex binds up to 4 ancestor joints (`StandardAttributes.SkinningJoints`: `Uint16Array(4 * V)`, `StandardAttributes.SkinningWeights`: `Float32Array(4 * V)` summing to $1.0$) with smooth cubic Hermite weight falloff along each branch segment.
|
|
200
|
+
3. **GPU Fluid-Driven Foliage Bone System (`FoliageWindRig` + `shader_foliage_wind_apply` + `GPUSceneWind`)**:
|
|
201
|
+
- **Data Tables (`ANIMATION_DATABASE_SPEC`)**:
|
|
202
|
+
- `animation_foliage_rigs` (`ANIMATION_FOLIAGE_RIG_STRUCT`): stores `joints_first`, `joint_count`, `root_node` (`transforms` row of the tree root), and `weight`.
|
|
203
|
+
- `animation_foliage_joints` (`ANIMATION_FOLIAGE_JOINT_STRUCT`, 64 B / 16 words per bone): stores static physical aeroelastic parameters (`rest_rotation`, unit `branch_axis` $\hat{\mathbf{d}}_j$, Euler-Bernoulli cantilever `compliance` $c_j$, `natural_frequency` $\omega_j$, `damping_ratio` $\zeta_j$, `max_angle` $\theta_{\max,j}$, `turbulence` $\tau_j$, `node`, `rig`) alongside persistent GPU-integrated dynamic state (`angular_displacement` $\boldsymbol{\theta}_j$, `angular_velocity` $\dot{\boldsymbol{\theta}}_j$, `flutter_phase` $\phi_j$).
|
|
204
|
+
- **GPU Compute Pass (`shader_foliage_wind_apply.js`)**:
|
|
205
|
+
- Dispatched inside `GPUAnimationManager.tick()` alongside `shader_animation_apply`, binding `scene_context.wind` via `wind_field_add_resources` and `chunk_wind_field_sample` (`WIND_FIELD_UNIFORM` switch).
|
|
206
|
+
- Reads each bone's world position $\mathbf{p}_{\text{ws}} = \text{joint\_node.global}[3].xyz$, samples the 3D fluid velocity $\mathbf{w}_{\text{ws}} = \text{wind\_field\_sample}(\mathbf{p}_{\text{ws}})$, and transforms $\mathbf{w}_{\text{ws}}$ into the tree root's model space $\mathbf{w}_{\text{model}}$.
|
|
207
|
+
- Computes cross-flow aerodynamic drag torque $\boldsymbol{\tau}_{\text{drag}} \propto (\hat{\mathbf{d}}_j \times \mathbf{w}_{\text{model}}) \cdot c_j(0.5 + 0.5\|\mathbf{w}_{\text{model}}\|)$ plus Strouhal vortex-shedding oscillation along the orthogonal basis $(\mathbf{e}_1, \mathbf{e}_2) \perp \hat{\mathbf{d}}_j$, with asymptotic soft saturation $\theta_{\max,j} \cdot x / (1 + x)$ so extreme fluid impulses never snap branches past $\theta_{\max,j}$.
|
|
208
|
+
- Integrates an unconditionally stable implicit 2nd-order damped harmonic spring-damper oscillator ($\ddot{\boldsymbol{\theta}} + 2\zeta\omega\dot{\boldsymbol{\theta}} + \omega^2(\boldsymbol{\theta} - \boldsymbol{\theta}_{\text{target}}) = \mathbf{0}$), writes $(\boldsymbol{\theta}_j, \dot{\boldsymbol{\theta}}_j, \phi_j)$ back to `animation_foliage_joints`, and accumulates the resulting local quaternion into `pose_accumulator` via `pose_accumulator_add_rotation`.
|
|
209
|
+
- Downstream `shader_animation_pose_resolve` $\to$ `graph_scene_update_transform_hierarchy` $\to$ `shader_skin_matrix_prep` $\to$ `GPUMeshSkinningContext` (dual-quaternion meshlet deformation + BLAS/TLAS BVH refit) executes unchanged with zero scale conflicts.
|
|
210
|
+
|
|
211
|
+
### 7.3 Procedural PBR `StandardShadeMaterial` Synthesis
|
|
212
|
+
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
|
+
1. **`make_bark_material(config)`**:
|
|
214
|
+
- 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(config)`**:
|
|
216
|
+
- Generates a botanical twig/leaf or conifer-needle cluster **Albedo + Alpha Cutout** texture (serrated/lobed/ovate/palmate/needle silhouettes, midrib & lateral venation, premultiplied RGBA compatible with Shade's `albedo_unpremultiply` and hashed alpha test), **Tangent-Space Normal Map** (vein relief), and **ORM Map** on a `StandardShadeMaterial` (`TransparencyMode.AlphaTested`, `ShadeDrawSide.Double`, `transmission_factor: 0.25`).
|
|
217
|
+
|
|
218
|
+
### 7.4 Multi-LOD Chain with Area-Compensated Foliage Decimation
|
|
219
|
+
Generates a configurable $N$-level LOD chain (default 4 levels: `LOD0`, `LOD1`, `LOD2`, `LOD3`):
|
|
220
|
+
- **Branch Hierarchy & Ring Reduction**:
|
|
221
|
+
- `LOD0`: All branch levels, full radial segments ($M_0 = 16 \to 4$), $100\%$ foliage cards ($2 \times 3$ folded V-cards).
|
|
222
|
+
- `LOD1`: Prunes finest sub-twigs below radius threshold, reduces radial segments by $0.65\times$, retains $55\%$ foliage cards ($2 \times 2$ V-cards).
|
|
223
|
+
- `LOD2`: Retains trunk + primary/secondary boughs, reduces radial segments by $0.4\times$, retains $28\%$ foliage cards (single-fold cards).
|
|
224
|
+
- `LOD3`: Coarse structural trunk/boughs + $12\%$ large cross-cluster canopy cards.
|
|
225
|
+
- **Golden-Ratio Stratified Decimation & Area Compensation**:
|
|
226
|
+
- Foliage attachments are filtered deterministically via Golden Ratio low-discrepancy rank $h_i = (i \cdot \varphi^{-1}) \bmod 1 < k_{\text{keep}}$, ensuring uniform thinning across every branch.
|
|
227
|
+
- Surviving cards are scaled around their petiole pivot by:
|
|
228
|
+
$$s_{\text{comp}}(k_{\text{keep}}) = k_{\text{keep}}^{-\eta}, \quad \eta = 0.42$$
|
|
229
|
+
preserving apparent optical density and crown silhouette across all LOD transitions.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 8. Module File Organization (`src/generation/foliage/`)
|
|
234
|
+
|
|
235
|
+
Following Meep's strict one-export-per-file (`PascalCase.js` for classes/enums, `snake_case.js` for pure functions) convention:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
src/generation/foliage/
|
|
239
|
+
config/
|
|
240
|
+
CrownEnvelopeType.js
|
|
241
|
+
PhyllotaxisMode.js
|
|
242
|
+
FoliageCardType.js
|
|
243
|
+
TreePreset.js
|
|
244
|
+
BranchLevelConfig.js
|
|
245
|
+
CrownConfig.js
|
|
246
|
+
FoliageConfig.js
|
|
247
|
+
BarkMaterialConfig.js
|
|
248
|
+
FoliageMaterialConfig.js
|
|
249
|
+
TreeWindConfig.js
|
|
250
|
+
TreeLODConfig.js
|
|
251
|
+
TreeSpeciesConfig.js (+ .spec.js)
|
|
252
|
+
presets/
|
|
253
|
+
make_tree_species_preset.js (+ .spec.js)
|
|
254
|
+
skeleton/
|
|
255
|
+
TreeSkeleton.js (+ .spec.js)
|
|
256
|
+
crown_envelope_evaluate.js (+ .spec.js)
|
|
257
|
+
spine_frame_double_reflection.js (+ .spec.js)
|
|
258
|
+
tree_skeleton_grow.js (+ .spec.js)
|
|
259
|
+
tree_skeleton_compute_pipe_radii.js (+ .spec.js)
|
|
260
|
+
tree_skeleton_assign_skin_joints.js (+ .spec.js)
|
|
261
|
+
mesh/
|
|
262
|
+
branch_collar_project.js (+ .spec.js)
|
|
263
|
+
branch_ring_triangulate.js (+ .spec.js)
|
|
264
|
+
tree_mesh_build_bark.js (+ .spec.js)
|
|
265
|
+
foliage_collect_attachments.js (+ .spec.js)
|
|
266
|
+
tree_mesh_build_foliage.js (+ .spec.js)
|
|
267
|
+
tree_mesh_apply_canopy_ao.js (+ .spec.js)
|
|
268
|
+
material/
|
|
269
|
+
make_bark_material.js (+ .spec.js)
|
|
270
|
+
make_foliage_material.js (+ .spec.js)
|
|
271
|
+
animation/
|
|
272
|
+
build_tree_wind_rig.js (+ .spec.js)
|
|
273
|
+
asset/
|
|
274
|
+
TreeLODAsset.js
|
|
275
|
+
TreeAsset.js
|
|
276
|
+
generate_tree.js (+ .spec.js)
|
|
277
|
+
place_tree.js (+ .spec.js)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 9. Adversarial Design Review & Required Revisions
|
|
283
|
+
|
|
284
|
+
An adversarial audit of §§1–8 against the `packages/meep-engine/src` implementation identified 10 critical invariants and edge cases, all resolved in the final design below:
|
|
285
|
+
|
|
286
|
+
1. **`Graph`, `Transform64`, and `Attribute` Integration (No `BinaryTopology` Contortion)**:
|
|
287
|
+
- *Finding*: `BinaryTopology` is a polygonal surface mesh structure with unordered edge endpoints (`v1`, `v2`), not a general-purpose directed graph.
|
|
288
|
+
- *Resolution*: `TreeSkeleton` uses Meep's directed `Graph` (`src/core/graph/v2/Graph.js`, `EdgeDirectionType.Forward`) for topology, `Transform64` (`src/engine/ecs/transform/Transform64.js`, `t64_look_rotation`) for node 3D positions, RMF bases (`[R, S, T]`), and cross-sectional radii, and `Attribute` (`src/shade/renderer/geometry/Attribute.js`) for per-node and per-segment buffers.
|
|
289
|
+
2. **Deep-Copy Isolation on `TreeSkeleton.copy()` and `clone()`**:
|
|
290
|
+
- *Finding*: Cloning a `TreeSkeleton` must not alias `Transform64` instances or `Attribute` typed arrays.
|
|
291
|
+
- *Resolution*: `TreeSkeleton.prototype.copy()` deep-copies `this.graph`, each `Transform64` in `this.node_transforms`, and all node/segment `Attribute` instances via `Attribute.prototype.copy()`.
|
|
292
|
+
3. **`PointHashGrid3` Non-Incremental Rebuild, Static `VISITED` Scratch, & XOR Hash Collisions**:
|
|
293
|
+
- *Finding*: `PointHashGrid3` uses a module-static `VISITED` array in `forEachNear` (forbidding nested calls) and Teschner XOR hashing (requiring exact distance filtering).
|
|
294
|
+
- *Resolution*: `tree_skeleton_grow` builds `PointHashGrid3` once with `cell_size = max_attraction_radius`, tracks consumed attraction points in a separate `Uint8Array(N_attract)` `alive` buffer, never nests `forEachNear`, and filters candidates by `alive[idx] === 1` and exact squared distance $d^2 \le r_{\text{attract}}^2$.
|
|
295
|
+
4. **Seeded Noise Offset & Mulberry32 Hash Avalanche**:
|
|
296
|
+
- *Finding*: `sdnoise3_array` and `curl_noise_3d` are unseeded, and `hash_mix2` / `hash_mix3` (`(a * 31 + b) | 0`) lack bit avalanche if divided directly by $2^{32}$.
|
|
297
|
+
- *Resolution*: All per-branch/per-node seeds mixed with `hash_mix3` are passed through `seededRandom` (Mulberry32 avalanche) before sampling floats, and all 3D noise evaluations add a seed-derived spatial offset $\mathbf{o}_{\text{seed}} \in [-500, 500]^3$.
|
|
298
|
+
5. **Lazy `MeshletGeometry` / `Prefab` Evaluation & Zero Degenerate Triangles**:
|
|
299
|
+
- *Finding*: `geometry_to_meshlets_meshoptimizer` asserts `MeshoptClusterizer.ready` (async WASM), and `meshlet_batch_to_bvh` asserts `root === 0`, which fails if `MeshoptClusterizer` strips any index-degenerate triangle (`i0 === i1 || i1 === i2 || i2 === i0`) or if a 0-triangle geometry is clusterized.
|
|
300
|
+
- *Resolution*:
|
|
301
|
+
- `TreeLODAsset.bark_meshlet_geometry`, `foliage_meshlet_geometry`, `scene_bundle`, and `prefab` are lazy memoized getters.
|
|
302
|
+
- `M_min >= 3` is enforced on all branch rings, tapered zero-radius branch tips use an $M$-triangle apex fan (zero degenerate triangles), and empty foliage sets `foliage_meshlet_geometry = null`.
|
|
303
|
+
6. **Branch Collar Projection & Dichotomous Fork Guards**:
|
|
304
|
+
- *Finding*: Steep insertion angles ($\alpha \to 0^\circ, 180^\circ$) cause `0/0` in $\mathbf{R}_{c,0}$ and unbounded axial ray pullback $\tau \to \infty$; large child radii ($R_c \approx R_p$) bunch vertices if clamped post-flare; terminal dichotomous splits should not project onto the lateral cylinder wall.
|
|
305
|
+
- *Resolution*: Fall back to `tube_frame_transport` when $\|\mathbf{T}_p - (\mathbf{T}_p \cdot \mathbf{T}_{c,0})\mathbf{T}_{c,0}\|^2 \le 10^{-8}$, clamp axial pullback $|\tau| \le 1.25 R_p$, scale collar flare radius prior to ring emission so $R_{\text{lateral}} \le 0.88 R_p$, and use direct terminal ring blending for terminal splits (`parent_attach_t >= 0.95`).
|
|
306
|
+
7. **Double-Reflection RMF Degeneracy Guards**:
|
|
307
|
+
- *Finding*: Coincident points ($c_1 \le 10^{-12}$) or pure lateral steps with unchanged tangent ($c_2 \le 10^{-12}$) divide by zero in Wang et al.'s double reflection.
|
|
308
|
+
- *Resolution*: Guard $c_1 \le 10^{-12}$ via `tube_frame_transport`, and when $c_2 \le 10^{-12}$ treat the second reflection as identity followed by Gram-Schmidt orthonormalization.
|
|
309
|
+
8. **Double-Sided Foliage Backface Normal Negation in `fragment_gbuffer.js`**:
|
|
310
|
+
- *Finding*: `fragment_gbuffer.js` negates `world_vertex_normal` when `dot(world_face_normal, view_direction) < 0`. Replacing card normals with pure radial crown normals causes back-facing sunlit cards to flip their normal into the dark trunk interior and can trigger Gram-Schmidt tangent singularities when $\mathbf{n} \parallel \mathbf{t}_{\text{uv}}$.
|
|
311
|
+
- *Resolution*: Orient card front faces outward ($\mathbf{U} \cdot \mathbf{n}_{\text{canopy}} \ge 0$), constrain `normal_puffiness` so $\mathbf{n}_{\text{vertex}} \cdot \mathbf{n}_{\text{face}} \ge 0.55$ (smooth V-fold dome + bounded skyward tilt), and encode macro volumetric crown shading in `StandardAttributes.Color` (`AO_crown * AO_local`).
|
|
312
|
+
9. **`StandardShadeMaterial` & `ShadeTexture` Pipeline Invariants**:
|
|
313
|
+
- *Finding*: Default `ambient_factors = LinearModifier(1, 1)` saturates `out.ambient` to `>= 1.0`; `transmission_factor > 0` makes cutout card corners cast refractive shadows in the path tracer; `ShadeImage` defaults to `AlphaMode.Straight` (which premultiplies on GPU upload) and `ColorSpace.SRGB`.
|
|
314
|
+
- *Resolution*: Set `ambient_factors.set(1, 0)` on both materials, keep `transmission_factor = 0` on cutout foliage, write dilated straight RGBA with `AlphaMode.Straight` on foliage albedo, and set `image.color_space = ColorSpace.None`, `image.alpha_mode = AlphaMode.Opaque`, `texture.color_space = ColorSpace.LinearSRGB` on normal and ORM textures.
|
|
315
|
+
10. **Zero-Defect `Skin`, `SceneBundle`, & GPU Fluid-Driven `FoliageWindRig` Playback**:
|
|
316
|
+
- *Finding*: `prefab_normalize_skin_frames` requires rigid bind frames (`frame_defect === 0`, `residual === 0`) and leaf mesh nodes (`obstructed.length === 0`); shipping baked keyframe wind clips would ignore Meep's 3D fluid dynamics simulation (`GPUSceneWind`); `prefab_place` does not register `FoliageWindRig`s automatically.
|
|
317
|
+
- *Resolution*: Author `tree_root` (`node 0`), joint nodes (`1..J`) with identity rest rotations `[0, 0, 0, 1]` and exact translation inverse-bind matrices $T(-\mathbf{p}_j)$, and leaf mesh nodes (`parent: 0`, identity local transform) sharing one `Skin`. `build_tree_wind_rig` authors a `FoliageWindRig` whose bones sample `GPUSceneWind` (`chunk_wind_field_sample`) in `shader_foliage_wind_apply`. `place_tree` registers the `FoliageWindRig` on `scene_context.animation_manager` with a position-desynchronized `flutter_phase`, and `unplace_tree` unregisters `foliage_rig_ids` before `prefab_unplace`.
|
|
318
|
+
|