@woosh/meep-engine 3.53.0 → 3.54.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/core/math/noise/worley_noise_2d.d.ts +14 -0
- package/src/core/math/noise/worley_noise_2d.d.ts.map +1 -0
- package/src/core/math/noise/worley_noise_2d.js +74 -0
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts +6 -1
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.js +363 -325
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts +93 -14
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +322 -183
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts +9 -0
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +110 -83
- package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts +42 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlas.d.ts.map +1 -0
- package/src/engine/{graphics3/decal/DecalAtlas.js → graphics/texture/atlas/SpriteAtlas.js} +202 -194
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts +12 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.d.ts.map +1 -0
- package/src/engine/graphics/texture/atlas/SpriteAtlasFill.js +30 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +7 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/TextureAtlas.js +11 -1
- package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts +52 -0
- package/src/engine/graphics/texture/atlas/sprite_atlas_border.d.ts.map +1 -0
- package/src/engine/{graphics3/decal/decal_atlas_border.js → graphics/texture/atlas/sprite_atlas_border.js} +69 -69
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +447 -450
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +9 -22
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +892 -951
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/generation/foliage/FOLIAGE_DESIGN.md +2 -1
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts +4 -3
- package/src/generation/foliage/config/BarkMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/BarkMaterialConfig.js +6 -6
- package/src/generation/foliage/config/FoliageBarkType.d.ts +11 -0
- package/src/generation/foliage/config/FoliageBarkType.d.ts.map +1 -0
- package/src/generation/foliage/config/FoliageBarkType.js +16 -0
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +58 -5
- package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
- package/src/generation/foliage/config/FoliageMaterialConfig.js +279 -181
- package/src/generation/foliage/index.d.ts +2 -1
- package/src/generation/foliage/index.js +44 -43
- package/src/generation/foliage/material/make_bark_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_bark_material.js +23 -95
- package/src/generation/foliage/material/make_foliage_material.d.ts +29 -3
- package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
- package/src/generation/foliage/material/make_foliage_material.js +605 -359
- package/src/generation/foliage/mesh/branch_collar_project.d.ts.map +1 -1
- package/src/generation/foliage/mesh/branch_collar_project.js +205 -203
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +15 -0
- package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
- package/src/generation/foliage/mesh/foliage_collect_attachments.js +569 -502
- package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1049 -1047
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +2 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
- package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +454 -415
- package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
- package/src/generation/foliage/presets/make_tree_species_preset.js +870 -837
- package/src/generation/foliage/skeleton/crown_envelope_evaluate.js +121 -121
- package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts +10 -7
- 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 +206 -179
- package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
- package/src/generation/foliage/skeleton/tree_skeleton_grow.js +1871 -1104
- package/src/shade/playground/foliage_wind/foliage_world.d.ts +6 -0
- package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
- package/src/shade/playground/foliage_wind/foliage_world.js +602 -593
- package/src/shade/playground/foliage_wind/index.html +260 -254
- package/src/shade/playground/foliage_wind/main.js +275 -263
- package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
- package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
- package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +3 -3
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +350 -294
- package/src/shade/renderer/hiz/generate_downsampler_code.d.ts +0 -2
- package/src/shade/renderer/hiz/generate_downsampler_code.d.ts.map +1 -1
- package/src/shade/renderer/hiz/generate_downsampler_code.js +99 -100
- package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts +15 -0
- package/src/shade/renderer/hiz/hzb_pick_alignment.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_pick_alignment.js +148 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts +28 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.d.ts.map +1 -0
- package/src/shade/renderer/hiz/hzb_plan_reduction_steps.js +58 -0
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +5 -5
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +57 -67
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +3 -3
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +1 -1
- package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.js +111 -112
- package/src/shade/renderer/hiz/shader_hzb_spd.d.ts +5 -0
- package/src/shade/renderer/hiz/shader_hzb_spd.d.ts.map +1 -0
- package/src/shade/renderer/hiz/shader_hzb_spd.js +160 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts +8 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +67 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts +7 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/FAR_FIELD_IRRADIANCE_SH_RESOURCE.js +13 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts +10 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/shader_project_far_field_irradiance_sh.js +72 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts +39 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/WORLD_LIGHT_CLUSTER.js +90 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts +12 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.js +56 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts +31 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.js +196 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts +10 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.js +163 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts +4 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.d.ts.map +1 -0
- package/src/shade/renderer/light/world_cluster/shader_world_cluster_cull_lights.js +137 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +4 -3
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts +4 -3
- package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles_avboit.js +28 -11
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts +9 -13
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_lighting.js +25 -20
- 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 +21 -38
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/depth/chunk_query_depth_from_screen_space_bb.js +62 -62
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts +6 -0
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/random/lowbias/chunk_hash_lowbias32_vec2u.js +19 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_get_mip_resolution.js +16 -10
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_hierarchical_raymarch.js +118 -117
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +41 -7
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -1
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +162 -58
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +10 -12
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +583 -606
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_sample.d.ts +24 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +640 -640
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +113 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +484 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts +50 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP.js +60 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts +25 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IRRADIANCE_CLIPMAP_STRUCT.js +47 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts +74 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/IrradianceCascadePlacement.js +173 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +26 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +83 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts +31 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_local_light.js +113 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts +121 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_sample.js +356 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts +16 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.js +191 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_classify_froxels.d.ts +16 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_classify_froxels.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_lighting_regimes.d.ts +23 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_lighting_regimes.d.ts.map +1 -0
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.js +1 -1
- package/src/engine/graphics3/decal/DecalAtlasFill.js +0 -32
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_froxel_centre_ws.js +0 -49
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi.js +0 -50
- package/src/shade/renderer/volumetrics/gi/chunk_volumetrics_gi_sample.js +0 -105
- package/src/shade/renderer/volumetrics/gi/graph_build_froxel_gi.js +0 -80
- package/src/shade/renderer/volumetrics/gi/shader_volumetrics_gi.js +0 -51
- package/src/shade/renderer/volumetrics/gi/volumetrics_gi_resources.js +0 -39
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +0 -121
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_irradiance.js +0 -237
|
@@ -1,502 +1,569 @@
|
|
|
1
|
-
import { GOLDEN_RATIO } from "../../../core/math/GOLDEN_RATIO.js";
|
|
2
|
-
import { PI2 } from "../../../core/math/PI2.js";
|
|
3
|
-
import { clamp } from "../../../core/math/clamp.js";
|
|
4
|
-
import { lerp } from "../../../core/math/lerp.js";
|
|
5
|
-
import { seededRandom } from "../../../core/math/random/seededRandom.js";
|
|
6
|
-
import { t64_look_rotation } from "../../../engine/ecs/transform/t64_look_rotation.js";
|
|
7
|
-
import { Transform64 } from "../../../engine/ecs/transform/Transform64.js";
|
|
8
|
-
import { Attribute } from "../../../shade/renderer/geometry/Attribute.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* @
|
|
29
|
-
* @property {
|
|
30
|
-
* @property {Float32Array}
|
|
31
|
-
* @property {Float32Array}
|
|
32
|
-
* @property {Float32Array}
|
|
33
|
-
* @property {Float32Array}
|
|
34
|
-
* @property {Float32Array}
|
|
35
|
-
* @property {Float32Array}
|
|
36
|
-
* @property {Float32Array}
|
|
37
|
-
* @property {Float32Array}
|
|
38
|
-
* @property {
|
|
39
|
-
* @property {Float32Array}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
1
|
+
import { GOLDEN_RATIO } from "../../../core/math/GOLDEN_RATIO.js";
|
|
2
|
+
import { PI2 } from "../../../core/math/PI2.js";
|
|
3
|
+
import { clamp } from "../../../core/math/clamp.js";
|
|
4
|
+
import { lerp } from "../../../core/math/lerp.js";
|
|
5
|
+
import { seededRandom } from "../../../core/math/random/seededRandom.js";
|
|
6
|
+
import { t64_look_rotation } from "../../../engine/ecs/transform/t64_look_rotation.js";
|
|
7
|
+
import { Transform64 } from "../../../engine/ecs/transform/Transform64.js";
|
|
8
|
+
import { Attribute } from "../../../shade/renderer/geometry/Attribute.js";
|
|
9
|
+
import { CrownEnvelopeType } from "../config/CrownEnvelopeType.js";
|
|
10
|
+
import { PhyllotaxisMode } from "../config/PhyllotaxisMode.js";
|
|
11
|
+
import { TreeSpeciesConfig } from "../config/TreeSpeciesConfig.js";
|
|
12
|
+
import { spine_frame_double_reflection } from "../skeleton/spine_frame_double_reflection.js";
|
|
13
|
+
import { tree_mesh_compute_branch_rings } from "./tree_mesh_build_bark.js";
|
|
14
|
+
|
|
15
|
+
const GOLDEN_CONJUGATE = 1.0 / GOLDEN_RATIO; // ~0.6180339887498949
|
|
16
|
+
const GOLDEN_ANGLE = PI2 / (GOLDEN_RATIO * GOLDEN_RATIO);
|
|
17
|
+
|
|
18
|
+
const SCRATCH_POS = new Float32Array(3);
|
|
19
|
+
const SCRATCH_TAN = new Float32Array(3);
|
|
20
|
+
const SCRATCH_P0 = new Float32Array(3);
|
|
21
|
+
const SCRATCH_T0 = new Float32Array(3);
|
|
22
|
+
const SCRATCH_R0 = new Float32Array(3);
|
|
23
|
+
const SCRATCH_RMF = new Float64Array(6);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Flat typed-array structure holding all phyllotactic foliage attachment points and oriented card frames.
|
|
27
|
+
*
|
|
28
|
+
* @typedef {Object} FoliageAttachmentSet
|
|
29
|
+
* @property {number} count number of foliage attachments
|
|
30
|
+
* @property {Float32Array} positions `count * 3` attachment world/local positions
|
|
31
|
+
* @property {Float32Array} forward `count * 3` unit card length axis F
|
|
32
|
+
* @property {Float32Array} up `count * 3` unit card outward normal U
|
|
33
|
+
* @property {Float32Array} right `count * 3` unit card width axis W = F x U (so W x F = +U)
|
|
34
|
+
* @property {Float32Array} scales `count` per-card size multiplier
|
|
35
|
+
* @property {Float32Array} ranks `count` golden-ratio low-discrepancy decimation rank in [0, 1)
|
|
36
|
+
* @property {Float32Array} phases `count` per-card wind phase in [0, 1)
|
|
37
|
+
* @property {Float32Array} branch_sway `count` parent branch sway weight in [0, 1]
|
|
38
|
+
* @property {Float32Array} color_jitter `count` per-card luminance/tint jitter in [-1, 1]
|
|
39
|
+
* @property {Float32Array} maturities `count` per-card ontogenetic leaf maturity in [0, 1] (0 = juvenile tip, 1 = mature base)
|
|
40
|
+
* @property {Float32Array} sun_exposure `count` per-card canopy solar irradiance exposure in [0, 1]
|
|
41
|
+
* @property {Uint8Array} variant_indices `count` assigned foliage atlas variant index in `[0, variant_count - 1]`
|
|
42
|
+
* @property {Uint16Array} joints `count * 2` `[j_primary, j_parent]`
|
|
43
|
+
* @property {Float32Array} weights `count * 2` `[w_primary, w_parent]`
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Generates phyllotactic foliage card attachment transforms along all eligible branches of a `TreeSkeleton`.
|
|
48
|
+
*
|
|
49
|
+
* @param {import("../skeleton/TreeSkeleton.js").TreeSkeleton} skeleton
|
|
50
|
+
* @param {TreeSpeciesConfig} [config]
|
|
51
|
+
* @returns {FoliageAttachmentSet}
|
|
52
|
+
*/
|
|
53
|
+
export function foliage_collect_attachments(skeleton, config = new TreeSpeciesConfig()) {
|
|
54
|
+
const species = config && config.isTreeSpeciesConfig ? config : TreeSpeciesConfig.from(config);
|
|
55
|
+
const fol = species.foliage;
|
|
56
|
+
if (!fol.enabled || skeleton.branch_count === 0) {
|
|
57
|
+
return {
|
|
58
|
+
count: 0,
|
|
59
|
+
transforms: [],
|
|
60
|
+
positions: new Float32Array(0),
|
|
61
|
+
forward: new Float32Array(0),
|
|
62
|
+
up: new Float32Array(0),
|
|
63
|
+
right: new Float32Array(0),
|
|
64
|
+
scales: new Float32Array(0),
|
|
65
|
+
ranks: new Float32Array(0),
|
|
66
|
+
phases: new Float32Array(0),
|
|
67
|
+
branch_sway: new Float32Array(0),
|
|
68
|
+
color_jitter: new Float32Array(0),
|
|
69
|
+
maturities: new Float32Array(0),
|
|
70
|
+
sun_exposure: new Float32Array(0),
|
|
71
|
+
variant_indices: new Uint8Array(0),
|
|
72
|
+
joints: new Uint16Array(0),
|
|
73
|
+
weights: new Float32Array(0),
|
|
74
|
+
joints4: new Uint16Array(0),
|
|
75
|
+
weights4: new Float32Array(0),
|
|
76
|
+
attr_ranks: Attribute.from(new Float32Array(0), 1, "foliage_ranks"),
|
|
77
|
+
attr_phases: Attribute.from(new Float32Array(0), 1, "foliage_phases"),
|
|
78
|
+
attr_branch_sway: Attribute.from(new Float32Array(0), 1, "foliage_branch_sway"),
|
|
79
|
+
attr_color_jitter: Attribute.from(new Float32Array(0), 1, "foliage_color_jitter"),
|
|
80
|
+
attr_maturities: Attribute.from(new Float32Array(0), 1, "foliage_maturities"),
|
|
81
|
+
attr_variant_indices: Attribute.from(new Uint8Array(0), 1, "foliage_variant_indices"),
|
|
82
|
+
attr_joints: Attribute.from(new Uint16Array(0), 2, "foliage_joints"),
|
|
83
|
+
attr_weights: Attribute.from(new Float32Array(0), 2, "foliage_weights")
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const rng = seededRandom((species.seed ^ 0x5A3C9E17) | 0);
|
|
88
|
+
const max_existing_level = Math.max(0, species.levels.length - 1);
|
|
89
|
+
const min_level = Math.min(fol.attach_min_level, max_existing_level);
|
|
90
|
+
const branch_rings = tree_mesh_compute_branch_rings(skeleton, species, species.lods?.[0]);
|
|
91
|
+
const variant_count = clamp((species.foliage_material?.variant_count ?? 4) | 0, 1, 16);
|
|
92
|
+
|
|
93
|
+
const crown = species.crown;
|
|
94
|
+
const is_conical_crown = crown.envelope_type === CrownEnvelopeType.Conical;
|
|
95
|
+
const cx = skeleton.crown_center[0];
|
|
96
|
+
const cy = skeleton.crown_center[1];
|
|
97
|
+
const cz = skeleton.crown_center[2];
|
|
98
|
+
const rx_crown = Math.max(0.5, skeleton.crown_radii[0]);
|
|
99
|
+
const ry = Math.max(0.5, skeleton.crown_radii[1]);
|
|
100
|
+
const rz_crown = Math.max(0.5, skeleton.crown_radii[2]);
|
|
101
|
+
const ref_card_len = Math.max(0.25, fol.card_length);
|
|
102
|
+
|
|
103
|
+
// First collect eligible branch edge chains via `skeleton.graph`
|
|
104
|
+
const eligible_branches = [];
|
|
105
|
+
for (let b = 0; b < skeleton.branch_count; b++) {
|
|
106
|
+
const level = skeleton.branch_level[b];
|
|
107
|
+
if (level < min_level) continue;
|
|
108
|
+
|
|
109
|
+
const nodes = [];
|
|
110
|
+
const edges = [];
|
|
111
|
+
skeleton.collect_branch_chain(b, nodes, edges);
|
|
112
|
+
if (edges.length === 0) continue;
|
|
113
|
+
|
|
114
|
+
const t_norms = new Array(nodes.length);
|
|
115
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
116
|
+
t_norms[i] = skeleton.node_t_norm(nodes[i]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
eligible_branches.push({ branch_id: b, level, nodes, edges, t_norms });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const lateral_count = Math.max(0, fol.cards_per_branch | 0);
|
|
123
|
+
const rosette_count = Math.max(0, fol.terminal_rosette_count | 0);
|
|
124
|
+
const per_branch = lateral_count + rosette_count;
|
|
125
|
+
const total_count = eligible_branches.length * per_branch;
|
|
126
|
+
|
|
127
|
+
/** @type {Transform64[]} */
|
|
128
|
+
const transforms = new Array(total_count);
|
|
129
|
+
const positions = new Float32Array(total_count * 3);
|
|
130
|
+
const forward = new Float32Array(total_count * 3);
|
|
131
|
+
const up = new Float32Array(total_count * 3);
|
|
132
|
+
const right = new Float32Array(total_count * 3);
|
|
133
|
+
const scales = new Float32Array(total_count);
|
|
134
|
+
const ranks = new Float32Array(total_count);
|
|
135
|
+
const phases = new Float32Array(total_count);
|
|
136
|
+
const branch_sway = new Float32Array(total_count);
|
|
137
|
+
const color_jitter = new Float32Array(total_count);
|
|
138
|
+
const maturities = new Float32Array(total_count);
|
|
139
|
+
const sun_exposure = new Float32Array(total_count);
|
|
140
|
+
const variant_indices = new Uint8Array(total_count);
|
|
141
|
+
const joints = new Uint16Array(total_count * 2);
|
|
142
|
+
const weights = new Float32Array(total_count * 2);
|
|
143
|
+
const joints4 = new Uint16Array(total_count * 4);
|
|
144
|
+
const weights4 = new Float32Array(total_count * 4);
|
|
145
|
+
|
|
146
|
+
let cursor = 0;
|
|
147
|
+
const bare = clamp(fol.bare_ratio, 0.0, 0.92);
|
|
148
|
+
|
|
149
|
+
for (let eb = 0; eb < eligible_branches.length; eb++) {
|
|
150
|
+
const item = eligible_branches[eb];
|
|
151
|
+
const level = item.level;
|
|
152
|
+
const nodes = item.nodes;
|
|
153
|
+
const edges = item.edges;
|
|
154
|
+
const t_norms = item.t_norms;
|
|
155
|
+
const b_rings = branch_rings.get(item.branch_id);
|
|
156
|
+
const b_len = Math.max(0.12, skeleton.branch_length[item.branch_id]);
|
|
157
|
+
const shoot_scale = clamp(b_len / (ref_card_len * 0.95), 0.22, 1.0);
|
|
158
|
+
const t_min = Math.max(bare, t_norms[0]);
|
|
159
|
+
const t_max = t_norms[t_norms.length - 1];
|
|
160
|
+
const base_phi = rng() * PI2;
|
|
161
|
+
const b_phase = skeleton.branch_phase_hash[item.branch_id];
|
|
162
|
+
|
|
163
|
+
for (let k = 0; k < per_branch; k++) {
|
|
164
|
+
const is_rosette = k >= lateral_count;
|
|
165
|
+
let t_attach = 1.0;
|
|
166
|
+
|
|
167
|
+
if (!is_rosette && lateral_count > 0) {
|
|
168
|
+
let u_k = (k + 0.5) / lateral_count;
|
|
169
|
+
if (fol.phyllotaxis_mode === PhyllotaxisMode.Opposite
|
|
170
|
+
|| fol.phyllotaxis_mode === PhyllotaxisMode.OppositeDecussate) {
|
|
171
|
+
const pair_idx = k >> 1;
|
|
172
|
+
const pair_total = Math.max(1, Math.ceil(lateral_count / 2));
|
|
173
|
+
u_k = (pair_idx + 0.5) / pair_total;
|
|
174
|
+
} else if (fol.phyllotaxis_mode === PhyllotaxisMode.Whorled) {
|
|
175
|
+
const w_size = Math.max(1, fol.whorl_count | 0);
|
|
176
|
+
const w_idx = Math.floor(k / w_size);
|
|
177
|
+
const w_total = Math.max(1, Math.ceil(lateral_count / w_size));
|
|
178
|
+
u_k = (w_idx + 0.5) / w_total;
|
|
179
|
+
}
|
|
180
|
+
t_attach = clamp(lerp(t_min, t_max * 0.92, u_k), t_min, t_max * 0.95);
|
|
181
|
+
} else {
|
|
182
|
+
const ros_idx = k - lateral_count;
|
|
183
|
+
const u_ros = (ros_idx + 0.5) / Math.max(1, rosette_count);
|
|
184
|
+
t_attach = clamp(lerp(Math.max(t_min, t_max * 0.88), t_max * 0.96, u_ros), t_min, t_max * 0.96);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Locate segment containing t_attach
|
|
188
|
+
let seg_idx = edges.length - 1;
|
|
189
|
+
for (let s = 0; s < edges.length; s++) {
|
|
190
|
+
if (t_attach >= t_norms[s] && t_attach <= t_norms[s + 1]) {
|
|
191
|
+
seg_idx = s;
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const edge_id = edges[seg_idx];
|
|
197
|
+
const v0 = nodes[seg_idx];
|
|
198
|
+
const v1 = nodes[seg_idx + 1];
|
|
199
|
+
const t0 = t_norms[seg_idx];
|
|
200
|
+
const t1 = t_norms[seg_idx + 1];
|
|
201
|
+
const local_u = clamp((t_attach - t0) / Math.max(1e-5, t1 - t0), 0.05, 0.95);
|
|
202
|
+
|
|
203
|
+
skeleton.evaluate_segment_position(SCRATCH_POS, 0, edge_id, local_u);
|
|
204
|
+
skeleton.evaluate_segment_tangent(SCRATCH_TAN, 0, edge_id, local_u);
|
|
205
|
+
skeleton.node_read_position(SCRATCH_P0, 0, v0);
|
|
206
|
+
skeleton.node_read_tangent(SCRATCH_T0, 0, v0);
|
|
207
|
+
skeleton.node_read_frame_r(SCRATCH_R0, 0, v0);
|
|
208
|
+
|
|
209
|
+
spine_frame_double_reflection(
|
|
210
|
+
SCRATCH_RMF, 0,
|
|
211
|
+
SCRATCH_P0[0], SCRATCH_P0[1], SCRATCH_P0[2],
|
|
212
|
+
SCRATCH_T0[0], SCRATCH_T0[1], SCRATCH_T0[2],
|
|
213
|
+
SCRATCH_R0[0], SCRATCH_R0[1], SCRATCH_R0[2],
|
|
214
|
+
SCRATCH_POS[0], SCRATCH_POS[1], SCRATCH_POS[2],
|
|
215
|
+
SCRATCH_TAN[0], SCRATCH_TAN[1], SCRATCH_TAN[2]
|
|
216
|
+
);
|
|
217
|
+
const rx = SCRATCH_RMF[0], ry_f = SCRATCH_RMF[1], rz = SCRATCH_RMF[2];
|
|
218
|
+
const sx = SCRATCH_RMF[3], sy_f = SCRATCH_RMF[4], sz = SCRATCH_RMF[5];
|
|
219
|
+
|
|
220
|
+
// Phyllotactic angle phi
|
|
221
|
+
let phi = base_phi;
|
|
222
|
+
if (is_rosette) {
|
|
223
|
+
const r_idx = k - lateral_count;
|
|
224
|
+
phi += (r_idx * PI2) / Math.max(1, rosette_count);
|
|
225
|
+
} else {
|
|
226
|
+
switch (fol.phyllotaxis_mode) {
|
|
227
|
+
case PhyllotaxisMode.AlternateDistichous:
|
|
228
|
+
phi += k * Math.PI;
|
|
229
|
+
break;
|
|
230
|
+
case PhyllotaxisMode.Tristichous:
|
|
231
|
+
phi += k * (PI2 / 3.0);
|
|
232
|
+
break;
|
|
233
|
+
case PhyllotaxisMode.Opposite:
|
|
234
|
+
phi += (k & 1) * Math.PI;
|
|
235
|
+
break;
|
|
236
|
+
case PhyllotaxisMode.OppositeDecussate:
|
|
237
|
+
phi += (k & 1) * Math.PI + (k >> 1) * (Math.PI * 0.5);
|
|
238
|
+
break;
|
|
239
|
+
case PhyllotaxisMode.Whorled: {
|
|
240
|
+
const w_size = Math.max(1, fol.whorl_count | 0);
|
|
241
|
+
const w_idx = Math.floor(k / w_size);
|
|
242
|
+
const sub_idx = k % w_size;
|
|
243
|
+
phi += (sub_idx * PI2) / w_size + (w_idx * Math.PI) / w_size;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case PhyllotaxisMode.SpiralGolden:
|
|
247
|
+
default:
|
|
248
|
+
phi += k * GOLDEN_ANGLE;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
phi += (rng() * 2.0 - 1.0) * fol.angular_jitter;
|
|
253
|
+
|
|
254
|
+
const cos_p = Math.cos(phi);
|
|
255
|
+
const sin_p = Math.sin(phi);
|
|
256
|
+
const drx = cos_p * rx + sin_p * sx;
|
|
257
|
+
const dry = cos_p * ry_f + sin_p * sy_f;
|
|
258
|
+
const drz = cos_p * rz + sin_p * sz;
|
|
259
|
+
|
|
260
|
+
// Anchor card stem origin on the actual meshed bark frustum chord [ra, rb]
|
|
261
|
+
// and interpolate the carrier frustum's exact 4-slot skinning weights
|
|
262
|
+
let px = SCRATCH_POS[0];
|
|
263
|
+
let py = SCRATCH_POS[1];
|
|
264
|
+
let pz = SCRATCH_POS[2];
|
|
265
|
+
let seg_tx = SCRATCH_TAN[0];
|
|
266
|
+
let seg_ty = SCRATCH_TAN[1];
|
|
267
|
+
let seg_tz = SCRATCH_TAN[2];
|
|
268
|
+
|
|
269
|
+
const c4 = cursor * 4;
|
|
270
|
+
const c2 = cursor * 2;
|
|
271
|
+
|
|
272
|
+
if (b_rings && b_rings.length >= 2) {
|
|
273
|
+
const ring_idx = Math.min(seg_idx, b_rings.length - 2);
|
|
274
|
+
const ra = b_rings[ring_idx];
|
|
275
|
+
const rb = b_rings[ring_idx + 1];
|
|
276
|
+
const xi = clamp((t_attach - ra.t_norm) / Math.max(1e-5, rb.t_norm - ra.t_norm), 0.05, 0.95);
|
|
277
|
+
|
|
278
|
+
px = lerp(ra.cx, rb.cx, xi);
|
|
279
|
+
py = lerp(ra.cy, rb.cy, xi);
|
|
280
|
+
pz = lerp(ra.cz, rb.cz, xi);
|
|
281
|
+
|
|
282
|
+
const dx_seg = rb.cx - ra.cx;
|
|
283
|
+
const dy_seg = rb.cy - ra.cy;
|
|
284
|
+
const dz_seg = rb.cz - ra.cz;
|
|
285
|
+
const seg_len = Math.hypot(dx_seg, dy_seg, dz_seg);
|
|
286
|
+
if (seg_len > 1e-6) {
|
|
287
|
+
seg_tx = dx_seg / seg_len;
|
|
288
|
+
seg_ty = dy_seg / seg_len;
|
|
289
|
+
seg_tz = dz_seg / seg_len;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Merge 4-slot skinning weights from ra (weight 1 - xi) and rb (weight xi)
|
|
293
|
+
const merged_j = [-1, -1, -1, -1, -1, -1, -1, -1];
|
|
294
|
+
const merged_w = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
295
|
+
let m_count = 0;
|
|
296
|
+
|
|
297
|
+
const accumulate_joint = (j_id, w_val) => {
|
|
298
|
+
if (w_val <= 1e-7) return;
|
|
299
|
+
for (let m = 0; m < m_count; m++) {
|
|
300
|
+
if (merged_j[m] === j_id) {
|
|
301
|
+
merged_w[m] += w_val;
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
merged_j[m_count] = j_id;
|
|
306
|
+
merged_w[m_count] = w_val;
|
|
307
|
+
m_count++;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const w_a = 1.0 - xi;
|
|
311
|
+
const w_b = xi;
|
|
312
|
+
accumulate_joint(ra.j0, ra.w0 * w_a);
|
|
313
|
+
accumulate_joint(ra.j1, ra.w1 * w_a);
|
|
314
|
+
accumulate_joint(ra.j2, ra.w2 * w_a);
|
|
315
|
+
accumulate_joint(ra.j3, ra.w3 * w_a);
|
|
316
|
+
accumulate_joint(rb.j0, rb.w0 * w_b);
|
|
317
|
+
accumulate_joint(rb.j1, rb.w1 * w_b);
|
|
318
|
+
accumulate_joint(rb.j2, rb.w2 * w_b);
|
|
319
|
+
accumulate_joint(rb.j3, rb.w3 * w_b);
|
|
320
|
+
|
|
321
|
+
// Sort descending by weight and normalize top 4
|
|
322
|
+
for (let a = 0; a < m_count - 1; a++) {
|
|
323
|
+
for (let b_sort = a + 1; b_sort < m_count; b_sort++) {
|
|
324
|
+
if (merged_w[b_sort] > merged_w[a]) {
|
|
325
|
+
const tw = merged_w[a];
|
|
326
|
+
merged_w[a] = merged_w[b_sort];
|
|
327
|
+
merged_w[b_sort] = tw;
|
|
328
|
+
const tj = merged_j[a];
|
|
329
|
+
merged_j[a] = merged_j[b_sort];
|
|
330
|
+
merged_j[b_sort] = tj;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const top_k = Math.min(4, m_count);
|
|
336
|
+
let w4_sum = 0.0;
|
|
337
|
+
for (let s = 0; s < top_k; s++) w4_sum += merged_w[s];
|
|
338
|
+
const inv_w4 = w4_sum > 1e-7 ? 1.0 / w4_sum : 1.0;
|
|
339
|
+
|
|
340
|
+
for (let s = 0; s < 4; s++) {
|
|
341
|
+
if (s < top_k) {
|
|
342
|
+
joints4[c4 + s] = merged_j[s];
|
|
343
|
+
weights4[c4 + s] = merged_w[s] * inv_w4;
|
|
344
|
+
} else {
|
|
345
|
+
joints4[c4 + s] = 0;
|
|
346
|
+
weights4[c4 + s] = 0.0;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Populate 2-slot legacy joints/weights normalized to sum to 1.0
|
|
351
|
+
const j_prim = top_k > 0 ? merged_j[0] : 0;
|
|
352
|
+
const j_par = top_k > 1 ? merged_j[1] : j_prim;
|
|
353
|
+
const w0_raw = top_k > 0 ? merged_w[0] : 1.0;
|
|
354
|
+
const w1_raw = top_k > 1 ? merged_w[1] : 0.0;
|
|
355
|
+
const w2_sum = w0_raw + w1_raw;
|
|
356
|
+
joints[c2] = j_prim;
|
|
357
|
+
joints[c2 + 1] = j_par;
|
|
358
|
+
weights[c2] = w2_sum > 1e-7 ? w0_raw / w2_sum : 1.0;
|
|
359
|
+
weights[c2 + 1] = w2_sum > 1e-7 ? w1_raw / w2_sum : 0.0;
|
|
360
|
+
} else {
|
|
361
|
+
const j_prim = skeleton.node_read_joint(v1, 0);
|
|
362
|
+
const j_par = skeleton.node_read_joint(v1, 1);
|
|
363
|
+
const w_prim = j_prim === j_par ? 1.0 : clamp(0.35 + 0.65 * t_attach, 0.0, 1.0);
|
|
364
|
+
joints[c2] = j_prim;
|
|
365
|
+
joints[c2 + 1] = j_par;
|
|
366
|
+
weights[c2] = w_prim;
|
|
367
|
+
weights[c2 + 1] = 1.0 - w_prim;
|
|
368
|
+
joints4[c4] = j_prim;
|
|
369
|
+
joints4[c4 + 1] = j_par;
|
|
370
|
+
weights4[c4] = w_prim;
|
|
371
|
+
weights4[c4 + 1] = 1.0 - w_prim;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Outward canopy normal n_canopy from crown center
|
|
375
|
+
let ncx = px - cx;
|
|
376
|
+
let ncy = (py - cy) + 0.35 * ry;
|
|
377
|
+
let ncz = pz - cz;
|
|
378
|
+
const nc_len = Math.sqrt(ncx * ncx + ncy * ncy + ncz * ncz);
|
|
379
|
+
if (nc_len > 1e-6) {
|
|
380
|
+
ncx /= nc_len;
|
|
381
|
+
ncy /= nc_len;
|
|
382
|
+
ncz /= nc_len;
|
|
383
|
+
} else {
|
|
384
|
+
ncx = 0.0;
|
|
385
|
+
ncy = 1.0;
|
|
386
|
+
ncz = 0.0;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const h_norm_card = clamp((py - crown.base_height) / Math.max(0.1, crown.height), 0.0, 1.0);
|
|
390
|
+
const w_apex_spire = is_conical_crown && h_norm_card > 0.72
|
|
391
|
+
? Math.pow(clamp((h_norm_card - 0.72) / 0.25, 0.0, 1.0), 1.35)
|
|
392
|
+
: 0.0;
|
|
393
|
+
|
|
394
|
+
// Initial card forward axis F along insertion angle from branch frustum tangent toward D_rad
|
|
395
|
+
const base_ins = is_rosette ? fol.insertion_angle * 0.55 : fol.insertion_angle;
|
|
396
|
+
const ins_angle = base_ins * (1.0 - 0.65 * w_apex_spire);
|
|
397
|
+
const cos_a = Math.cos(ins_angle);
|
|
398
|
+
const sin_a = Math.sin(ins_angle);
|
|
399
|
+
let fx = cos_a * seg_tx + sin_a * drx;
|
|
400
|
+
let fy = cos_a * seg_ty + sin_a * dry;
|
|
401
|
+
let fz = cos_a * seg_tz + sin_a * drz;
|
|
402
|
+
|
|
403
|
+
// Blend phototropism (outward/sky), gravitropism (downward droop along -Y), and orthotropic apical candle spire
|
|
404
|
+
const grav_atten = 1.0 - 0.90 * w_apex_spire;
|
|
405
|
+
const out_atten = 1.0 - 0.75 * w_apex_spire;
|
|
406
|
+
fx += fol.phototropism * 0.45 * out_atten * ncx + (rng() * 2.0 - 1.0) * fol.angular_jitter * 0.35 * out_atten;
|
|
407
|
+
fy += fol.phototropism * 0.25 * Math.max(0.0, ncy) - fol.gravitropism * 0.85 * grav_atten;
|
|
408
|
+
fz += fol.phototropism * 0.45 * out_atten * ncz + (rng() * 2.0 - 1.0) * fol.angular_jitter * 0.35 * out_atten;
|
|
409
|
+
|
|
410
|
+
if (w_apex_spire > 1e-4) {
|
|
411
|
+
const w_spire = clamp(w_apex_spire * (is_rosette ? 0.92 : 0.78), 0.0, 0.94);
|
|
412
|
+
fx = lerp(fx, -0.15 * ncx, w_spire);
|
|
413
|
+
fy = lerp(fy, 1.0, w_spire);
|
|
414
|
+
fz = lerp(fz, -0.15 * ncz, w_spire);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const f_len = Math.sqrt(fx * fx + fy * fy + fz * fz);
|
|
418
|
+
if (f_len > 1e-8) {
|
|
419
|
+
fx /= f_len;
|
|
420
|
+
fy /= f_len;
|
|
421
|
+
fz /= f_len;
|
|
422
|
+
} else {
|
|
423
|
+
fx = drx;
|
|
424
|
+
fy = dry;
|
|
425
|
+
fz = drz;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Desired card upward normal U: blend of world +Y and outward canopy normal n_canopy
|
|
429
|
+
let ux = ncx * 0.45;
|
|
430
|
+
let uy = 0.65 + ncy * 0.35;
|
|
431
|
+
let uz = ncz * 0.45;
|
|
432
|
+
// Gram-Schmidt orthogonalize U against F
|
|
433
|
+
const dot_uf = ux * fx + uy * fy + uz * fz;
|
|
434
|
+
ux -= dot_uf * fx;
|
|
435
|
+
uy -= dot_uf * fy;
|
|
436
|
+
uz -= dot_uf * fz;
|
|
437
|
+
const u_len = Math.sqrt(ux * ux + uy * uy + uz * uz);
|
|
438
|
+
if (u_len > 1e-6) {
|
|
439
|
+
ux /= u_len;
|
|
440
|
+
uy /= u_len;
|
|
441
|
+
uz /= u_len;
|
|
442
|
+
} else {
|
|
443
|
+
// Fallback perpendicular to F
|
|
444
|
+
if (Math.abs(fy) < 0.9) {
|
|
445
|
+
ux = -fz;
|
|
446
|
+
uy = 0.0;
|
|
447
|
+
uz = fx;
|
|
448
|
+
} else {
|
|
449
|
+
ux = 1.0;
|
|
450
|
+
uy = 0.0;
|
|
451
|
+
uz = 0.0;
|
|
452
|
+
}
|
|
453
|
+
const d2 = ux * fx + uy * fy + uz * fz;
|
|
454
|
+
ux -= d2 * fx;
|
|
455
|
+
uy -= d2 * fy;
|
|
456
|
+
uz -= d2 * fz;
|
|
457
|
+
const l2 = Math.sqrt(ux * ux + uy * uy + uz * uz);
|
|
458
|
+
ux /= l2;
|
|
459
|
+
uy /= l2;
|
|
460
|
+
uz /= l2;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Enforce outward/sky hemisphere alignment: dot(U, n_canopy + (0, 0.5, 0)) >= 0
|
|
464
|
+
if (ux * ncx + uy * (ncy + 0.5) + uz * ncz < 0.0) {
|
|
465
|
+
ux = -ux;
|
|
466
|
+
uy = -uy;
|
|
467
|
+
uz = -uz;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// W = F x U so that (W, F) card triangles have face normal W x F = +U!
|
|
471
|
+
const wx = fy * uz - fz * uy;
|
|
472
|
+
const wy = fz * ux - fx * uz;
|
|
473
|
+
const wz = fx * uy - fy * ux;
|
|
474
|
+
|
|
475
|
+
const c3 = cursor * 3;
|
|
476
|
+
|
|
477
|
+
positions[c3] = px;
|
|
478
|
+
positions[c3 + 1] = py;
|
|
479
|
+
positions[c3 + 2] = pz;
|
|
480
|
+
|
|
481
|
+
forward[c3] = fx;
|
|
482
|
+
forward[c3 + 1] = fy;
|
|
483
|
+
forward[c3 + 2] = fz;
|
|
484
|
+
|
|
485
|
+
up[c3] = ux;
|
|
486
|
+
up[c3 + 1] = uy;
|
|
487
|
+
up[c3 + 2] = uz;
|
|
488
|
+
|
|
489
|
+
right[c3] = wx;
|
|
490
|
+
right[c3 + 1] = wy;
|
|
491
|
+
right[c3 + 2] = wz;
|
|
492
|
+
|
|
493
|
+
const apex_env_scale = is_conical_crown && h_norm_card > 0.70
|
|
494
|
+
? lerp(1.0, 0.24, Math.pow(clamp((h_norm_card - 0.70) / 0.28, 0.0, 1.0), 1.15))
|
|
495
|
+
: 1.0;
|
|
496
|
+
const scale_var = 1.0 + (rng() * 2.0 - 1.0) * fol.size_variance;
|
|
497
|
+
const card_scale = Math.max(
|
|
498
|
+
0.18,
|
|
499
|
+
scale_var * (is_rosette ? 0.92 : 1.0) * Math.min(shoot_scale, apex_env_scale)
|
|
500
|
+
);
|
|
501
|
+
scales[cursor] = card_scale;
|
|
502
|
+
|
|
503
|
+
const t64 = new Transform64();
|
|
504
|
+
t64.setTranslation(px, py, pz);
|
|
505
|
+
t64_look_rotation(t64, fx, fy, fz, ux, uy, uz);
|
|
506
|
+
t64.setScaleScalar(card_scale);
|
|
507
|
+
t64.updateMatrix();
|
|
508
|
+
transforms[cursor] = t64;
|
|
509
|
+
|
|
510
|
+
// Golden-ratio low-discrepancy rank in [0, 1)
|
|
511
|
+
ranks[cursor] = ((cursor * GOLDEN_CONJUGATE) + b_phase * 0.13) % 1.0;
|
|
512
|
+
phases[cursor] = (b_phase + k * 0.17) % 1.0;
|
|
513
|
+
branch_sway[cursor] = clamp((level + t_attach) * 0.28, 0.1, 1.0);
|
|
514
|
+
const c_jit = rng() * 2.0 - 1.0;
|
|
515
|
+
color_jitter[cursor] = c_jit;
|
|
516
|
+
|
|
517
|
+
// Ontogenetic leaf maturity mu_i in [0, 1]:
|
|
518
|
+
// Acropetal shoot progression (terminal rosette / distal tip -> 0 juvenile, basal nodes -> 1 mature)
|
|
519
|
+
// combined with crown shell periphery (outer shell -> younger shoots, inner core -> older shade leaves)
|
|
520
|
+
const u_shoot = is_rosette
|
|
521
|
+
? clamp(0.88 + 0.12 * ((k - lateral_count + 0.5) / Math.max(1, rosette_count)), 0.88, 1.0)
|
|
522
|
+
: clamp((t_attach - t_min) / Math.max(1e-4, t_max * 0.92 - t_min), 0.0, 1.0);
|
|
523
|
+
const ndx_c = (px - cx) / rx_crown;
|
|
524
|
+
const ndy_c = (py - cy) / ry;
|
|
525
|
+
const ndz_c = (pz - cz) / rz_crown;
|
|
526
|
+
const rho_shell = clamp(Math.sqrt(ndx_c * ndx_c + ndy_c * ndy_c + ndz_c * ndz_c), 0.0, 1.0);
|
|
527
|
+
const maturity = clamp(
|
|
528
|
+
0.66 * (1.0 - u_shoot) + 0.24 * (1.0 - rho_shell) + 0.05 + 0.07 * c_jit,
|
|
529
|
+
0.0,
|
|
530
|
+
1.0
|
|
531
|
+
);
|
|
532
|
+
const sun_exp = clamp(0.62 * rho_shell + 0.38 * h_norm_card, 0.0, 1.0);
|
|
533
|
+
maturities[cursor] = maturity;
|
|
534
|
+
sun_exposure[cursor] = sun_exp;
|
|
535
|
+
variant_indices[cursor] = clamp(Math.floor(maturity * variant_count), 0, variant_count - 1);
|
|
536
|
+
|
|
537
|
+
cursor++;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return {
|
|
542
|
+
count: cursor,
|
|
543
|
+
transforms,
|
|
544
|
+
positions,
|
|
545
|
+
forward,
|
|
546
|
+
up,
|
|
547
|
+
right,
|
|
548
|
+
scales,
|
|
549
|
+
ranks,
|
|
550
|
+
phases,
|
|
551
|
+
branch_sway,
|
|
552
|
+
color_jitter,
|
|
553
|
+
maturities,
|
|
554
|
+
sun_exposure,
|
|
555
|
+
variant_indices,
|
|
556
|
+
joints,
|
|
557
|
+
weights,
|
|
558
|
+
joints4,
|
|
559
|
+
weights4,
|
|
560
|
+
attr_ranks: Attribute.from(ranks, 1, "foliage_ranks"),
|
|
561
|
+
attr_phases: Attribute.from(phases, 1, "foliage_phases"),
|
|
562
|
+
attr_branch_sway: Attribute.from(branch_sway, 1, "foliage_branch_sway"),
|
|
563
|
+
attr_color_jitter: Attribute.from(color_jitter, 1, "foliage_color_jitter"),
|
|
564
|
+
attr_maturities: Attribute.from(maturities, 1, "foliage_maturities"),
|
|
565
|
+
attr_variant_indices: Attribute.from(variant_indices, 1, "foliage_variant_indices"),
|
|
566
|
+
attr_joints: Attribute.from(joints, 2, "foliage_joints"),
|
|
567
|
+
attr_weights: Attribute.from(weights, 2, "foliage_weights")
|
|
568
|
+
};
|
|
569
|
+
}
|