@zephyr3d/scene 0.9.26 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (506) hide show
  1. package/README.md +60 -27
  2. package/dist/animation/animation_bank.js +634 -0
  3. package/dist/animation/animation_bank.js.map +1 -0
  4. package/dist/animation/animation_bank_gpu.js +256 -0
  5. package/dist/animation/animation_bank_gpu.js.map +1 -0
  6. package/dist/animation/animationset.js +146 -30
  7. package/dist/animation/animationset.js.map +1 -1
  8. package/dist/animation/cloth/gpu_cloth_component.js +406 -0
  9. package/dist/animation/cloth/gpu_cloth_component.js.map +1 -0
  10. package/dist/animation/cloth/gpu_cloth_system.js +332 -202
  11. package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
  12. package/dist/animation/gpu_animation_driver.js +289 -0
  13. package/dist/animation/gpu_animation_driver.js.map +1 -0
  14. package/dist/animation/joint_dynamics/collision.js +112 -1
  15. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  16. package/dist/animation/joint_dynamics/controller.js +6 -0
  17. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  18. package/dist/animation/joint_dynamics/joint_dynamics_system.js +11 -0
  19. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  20. package/dist/animation/joint_dynamics/solver.js +50 -12
  21. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  22. package/dist/animation/joint_dynamics/types.js.map +1 -1
  23. package/dist/animation/skeleton.js +300 -56
  24. package/dist/animation/skeleton.js.map +1 -1
  25. package/dist/animation/skin_palette_atlas.js +252 -0
  26. package/dist/animation/skin_palette_atlas.js.map +1 -0
  27. package/dist/animation/spring/multi_chain_spring_system.js +298 -38
  28. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  29. package/dist/animation/spring/spring_chain.js +2 -0
  30. package/dist/animation/spring/spring_chain.js.map +1 -1
  31. package/dist/animation/spring/spring_collider.js +159 -21
  32. package/dist/animation/spring/spring_collider.js.map +1 -1
  33. package/dist/animation/spring/spring_particle.js +1 -0
  34. package/dist/animation/spring/spring_particle.js.map +1 -1
  35. package/dist/animation/spring/spring_solver.js +173 -0
  36. package/dist/animation/spring/spring_solver.js.map +1 -0
  37. package/dist/animation/spring/spring_system.js +249 -24
  38. package/dist/animation/spring/spring_system.js.map +1 -1
  39. package/dist/animation/spring_modifier.js +32 -1
  40. package/dist/animation/spring_modifier.js.map +1 -1
  41. package/dist/app/app.js +26 -0
  42. package/dist/app/app.js.map +1 -1
  43. package/dist/app/engine.js +86 -15
  44. package/dist/app/engine.js.map +1 -1
  45. package/dist/app/gamepad.js +191 -0
  46. package/dist/app/gamepad.js.map +1 -0
  47. package/dist/app/inputactions.js +271 -0
  48. package/dist/app/inputactions.js.map +1 -0
  49. package/dist/app/inputmgr.js +331 -22
  50. package/dist/app/inputmgr.js.map +1 -1
  51. package/dist/app/loading.js +138 -0
  52. package/dist/app/loading.js.map +1 -0
  53. package/dist/app/pipelinecache.js +209 -0
  54. package/dist/app/pipelinecache.js.map +1 -0
  55. package/dist/app/runtimescript.js +25 -0
  56. package/dist/app/runtimescript.js.map +1 -1
  57. package/dist/app/scriptingsystem.js +54 -0
  58. package/dist/app/scriptingsystem.js.map +1 -1
  59. package/dist/app/scriptregistry.js +7 -2
  60. package/dist/app/scriptregistry.js.map +1 -1
  61. package/dist/asset/asset_manifest.js +59 -0
  62. package/dist/asset/asset_manifest.js.map +1 -0
  63. package/dist/asset/asset_preload.js +258 -0
  64. package/dist/asset/asset_preload.js.map +1 -0
  65. package/dist/asset/assetmanager.js +117 -65
  66. package/dist/asset/assetmanager.js.map +1 -1
  67. package/dist/asset/loaders/ktx2/basis/LICENSE +201 -0
  68. package/dist/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  69. package/dist/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  70. package/dist/asset/loaders/ktx2/basis_location.js +17 -0
  71. package/dist/asset/loaders/ktx2/basis_location.js.map +1 -0
  72. package/dist/asset/loaders/ktx2/ktx2_loader.js +88 -0
  73. package/dist/asset/loaders/ktx2/ktx2_loader.js.map +1 -0
  74. package/dist/asset/loaders/ktx2/ktx2_targets.js +118 -0
  75. package/dist/asset/loaders/ktx2/ktx2_targets.js.map +1 -0
  76. package/dist/asset/loaders/ktx2/transcoder_pool.js +259 -0
  77. package/dist/asset/loaders/ktx2/transcoder_pool.js.map +1 -0
  78. package/dist/asset/mesh_lod_builder.js +104 -0
  79. package/dist/asset/mesh_lod_builder.js.map +1 -0
  80. package/dist/asset/mesh_settings.js +111 -0
  81. package/dist/asset/mesh_settings.js.map +1 -0
  82. package/dist/asset/meshopt_decoder.js +18 -0
  83. package/dist/asset/meshopt_decoder.js.map +1 -0
  84. package/dist/asset/meshopt_simplifier.js +26 -0
  85. package/dist/asset/meshopt_simplifier.js.map +1 -0
  86. package/dist/asset/model.js +177 -3
  87. package/dist/asset/model.js.map +1 -1
  88. package/dist/asset/texture_settings.js +231 -0
  89. package/dist/asset/texture_settings.js.map +1 -0
  90. package/dist/asset/zmsh_binary.js +131 -0
  91. package/dist/asset/zmsh_binary.js.map +1 -0
  92. package/dist/asset/zsdf_binary.js +111 -0
  93. package/dist/asset/zsdf_binary.js.map +1 -0
  94. package/dist/blitter/bilateralblur.js +1 -2
  95. package/dist/blitter/bilateralblur.js.map +1 -1
  96. package/dist/blitter/gaussianblur.js +1 -6
  97. package/dist/blitter/gaussianblur.js.map +1 -1
  98. package/dist/camera/base.js +31 -10
  99. package/dist/camera/base.js.map +1 -1
  100. package/dist/camera/camera.js +178 -200
  101. package/dist/camera/camera.js.map +1 -1
  102. package/dist/camera/follow.js +342 -0
  103. package/dist/camera/follow.js.map +1 -0
  104. package/dist/camera/fps.js +9 -7
  105. package/dist/camera/fps.js.map +1 -1
  106. package/dist/camera/orbit.js +46 -19
  107. package/dist/camera/orbit.js.map +1 -1
  108. package/dist/index.d.ts +30475 -19865
  109. package/dist/index.js +67 -12
  110. package/dist/index.js.map +1 -1
  111. package/dist/material/blinn.js +3 -0
  112. package/dist/material/blinn.js.map +1 -1
  113. package/dist/material/eye.js +1 -1
  114. package/dist/material/eye.js.map +1 -1
  115. package/dist/material/hair.js +2 -3
  116. package/dist/material/hair.js.map +1 -1
  117. package/dist/material/hairstrand.js +235 -235
  118. package/dist/material/hairstrand.js.map +1 -1
  119. package/dist/material/lambert.js +4 -1
  120. package/dist/material/lambert.js.map +1 -1
  121. package/dist/material/material.js +362 -300
  122. package/dist/material/material.js.map +1 -1
  123. package/dist/material/meshmaterial.js +118 -45
  124. package/dist/material/meshmaterial.js.map +1 -1
  125. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  126. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  127. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  128. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  129. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +34 -61
  130. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  131. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -2
  132. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  133. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +2 -1
  134. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  135. package/dist/material/mixins/lit.js +223 -83
  136. package/dist/material/mixins/lit.js.map +1 -1
  137. package/dist/material/mixins/pbr/common.js +31 -206
  138. package/dist/material/mixins/pbr/common.js.map +1 -1
  139. package/dist/material/mtoon.js +1 -1
  140. package/dist/material/mtoon.js.map +1 -1
  141. package/dist/material/pbrmr.js +3 -0
  142. package/dist/material/pbrmr.js.map +1 -1
  143. package/dist/material/pbrsg.js +3 -0
  144. package/dist/material/pbrsg.js.map +1 -1
  145. package/dist/material/sdf_debug.js +78 -0
  146. package/dist/material/sdf_debug.js.map +1 -0
  147. package/dist/material/shader/helper.js +733 -190
  148. package/dist/material/shader/helper.js.map +1 -1
  149. package/dist/material/shader/terrain_blend.js +204 -43
  150. package/dist/material/shader/terrain_blend.js.map +1 -1
  151. package/dist/material/skin.js +331 -297
  152. package/dist/material/skin.js.map +1 -1
  153. package/dist/material/skinprofile.js +1058 -0
  154. package/dist/material/skinprofile.js.map +1 -0
  155. package/dist/material/sss.js +353 -0
  156. package/dist/material/sss.js.map +1 -0
  157. package/dist/material/sss_kernel.js +265 -0
  158. package/dist/material/sss_kernel.js.map +1 -0
  159. package/dist/material/sssprofile.js +879 -0
  160. package/dist/material/sssprofile.js.map +1 -0
  161. package/dist/material/subsurfaceprofile.js +4 -8
  162. package/dist/material/subsurfaceprofile.js.map +1 -1
  163. package/dist/material/terrain-cm.js +464 -188
  164. package/dist/material/terrain-cm.js.map +1 -1
  165. package/dist/material/unlit.js +3 -0
  166. package/dist/material/unlit.js.map +1 -1
  167. package/dist/material/water.js +2009 -201
  168. package/dist/material/water.js.map +1 -1
  169. package/dist/node_modules/meshoptimizer/LICENSE +21 -0
  170. package/dist/node_modules/meshoptimizer/meshopt_decoder.js +197 -0
  171. package/dist/node_modules/meshoptimizer/meshopt_decoder.js.map +1 -0
  172. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js +677 -0
  173. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js.map +1 -0
  174. package/dist/physics/character.js +226 -0
  175. package/dist/physics/character.js.map +1 -0
  176. package/dist/physics/collider.js +209 -0
  177. package/dist/physics/collider.js.map +1 -0
  178. package/dist/physics/events.js +79 -0
  179. package/dist/physics/events.js.map +1 -0
  180. package/dist/physics/joint.js +272 -0
  181. package/dist/physics/joint.js.map +1 -0
  182. package/dist/physics/node_physics.js +234 -0
  183. package/dist/physics/node_physics.js.map +1 -0
  184. package/dist/physics/part.js +91 -0
  185. package/dist/physics/part.js.map +1 -0
  186. package/dist/physics/rigid_body.js +379 -0
  187. package/dist/physics/rigid_body.js.map +1 -0
  188. package/dist/physics/vehicle.js +335 -0
  189. package/dist/physics/vehicle.js.map +1 -0
  190. package/dist/physics/world.js +25 -0
  191. package/dist/physics/world.js.map +1 -0
  192. package/dist/posteffect/bloom.js +49 -14
  193. package/dist/posteffect/bloom.js.map +1 -1
  194. package/dist/posteffect/motionblur.js +668 -63
  195. package/dist/posteffect/motionblur.js.map +1 -1
  196. package/dist/posteffect/posteffect.js +12 -1
  197. package/dist/posteffect/posteffect.js.map +1 -1
  198. package/dist/posteffect/postsss.js +572 -0
  199. package/dist/posteffect/postsss.js.map +1 -0
  200. package/dist/posteffect/sao.js +48 -50
  201. package/dist/posteffect/sao.js.map +1 -1
  202. package/dist/posteffect/skinsss.js +605 -355
  203. package/dist/posteffect/skinsss.js.map +1 -1
  204. package/dist/posteffect/ssgi.js +91 -162
  205. package/dist/posteffect/ssgi.js.map +1 -1
  206. package/dist/posteffect/ssr.js +3 -11
  207. package/dist/posteffect/ssr.js.map +1 -1
  208. package/dist/posteffect/sss.js +34 -15
  209. package/dist/posteffect/sss.js.map +1 -1
  210. package/dist/posteffect/taa.js +1 -0
  211. package/dist/posteffect/taa.js.map +1 -1
  212. package/dist/render/abuffer_oit.js +40 -39
  213. package/dist/render/abuffer_oit.js.map +1 -1
  214. package/dist/render/clipmap.js +328 -62
  215. package/dist/render/clipmap.js.map +1 -1
  216. package/dist/render/cluster_light.js +958 -224
  217. package/dist/render/cluster_light.js.map +1 -1
  218. package/dist/render/cull_visitor.js +26 -5
  219. package/dist/render/cull_visitor.js.map +1 -1
  220. package/dist/render/debug_views.js +37 -0
  221. package/dist/render/debug_views.js.map +1 -0
  222. package/dist/render/depthpass.js +5 -1
  223. package/dist/render/depthpass.js.map +1 -1
  224. package/dist/render/drawable_mixin.js +53 -6
  225. package/dist/render/drawable_mixin.js.map +1 -1
  226. package/dist/render/dualdepthpeeling_oit.js +53 -53
  227. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  228. package/dist/render/envlight.js +196 -113
  229. package/dist/render/envlight.js.map +1 -1
  230. package/dist/render/fbm_wavegenerator.js +8 -13
  231. package/dist/render/fbm_wavegenerator.js.map +1 -1
  232. package/dist/render/fft_wavegenerator.js +268 -136
  233. package/dist/render/fft_wavegenerator.js.map +1 -1
  234. package/dist/render/gerstner_wavegenerator.js +113 -28
  235. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  236. package/dist/render/gi/probe_volume.js +1334 -0
  237. package/dist/render/gi/probe_volume.js.map +1 -0
  238. package/dist/render/gi/scene_gi.js +282 -0
  239. package/dist/render/gi/scene_gi.js.map +1 -0
  240. package/dist/render/gi/voxel_atlas.js +198 -0
  241. package/dist/render/gi/voxel_atlas.js.map +1 -0
  242. package/dist/render/gi/voxel_lighting.js +652 -0
  243. package/dist/render/gi/voxel_lighting.js.map +1 -0
  244. package/dist/render/gi/voxel_scene.js +642 -0
  245. package/dist/render/gi/voxel_scene.js.map +1 -0
  246. package/dist/render/gi/voxelize_pass.js +223 -0
  247. package/dist/render/gi/voxelize_pass.js.map +1 -0
  248. package/dist/render/globalbindgroup_allocator.js +3 -2
  249. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  250. package/dist/render/gpu_picking.js +9 -36
  251. package/dist/render/gpu_picking.js.map +1 -1
  252. package/dist/render/hzb.js +80 -22
  253. package/dist/render/hzb.js.map +1 -1
  254. package/dist/render/instance_culling.js +499 -0
  255. package/dist/render/instance_culling.js.map +1 -0
  256. package/dist/render/lightpass.js +23 -9
  257. package/dist/render/lightpass.js.map +1 -1
  258. package/dist/render/lod.js +46 -0
  259. package/dist/render/lod.js.map +1 -0
  260. package/dist/render/oit.js +11 -11
  261. package/dist/render/oit.js.map +1 -1
  262. package/dist/render/primitive.js +301 -9
  263. package/dist/render/primitive.js.map +1 -1
  264. package/dist/render/primitive_readback.js +209 -0
  265. package/dist/render/primitive_readback.js.map +1 -0
  266. package/dist/render/render_queue.js +198 -11
  267. package/dist/render/render_queue.js.map +1 -1
  268. package/dist/render/renderer.js +14 -7
  269. package/dist/render/renderer.js.map +1 -1
  270. package/dist/render/rendergraph/blackboard.js +15 -1
  271. package/dist/render/rendergraph/blackboard.js.map +1 -1
  272. package/dist/render/rendergraph/executor.js +136 -0
  273. package/dist/render/rendergraph/executor.js.map +1 -1
  274. package/dist/render/rendergraph/forward_plus_builder.js +585 -59
  275. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  276. package/dist/render/rendergraph/frame_resource_requirements.js +1 -0
  277. package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -1
  278. package/dist/render/rendergraph/history_resources.js +8 -1
  279. package/dist/render/rendergraph/history_resources.js.map +1 -1
  280. package/dist/render/rendergraph/scene_render_context.js +31 -2
  281. package/dist/render/rendergraph/scene_render_context.js.map +1 -1
  282. package/dist/render/rendergraph/types.js.map +1 -1
  283. package/dist/render/renderpass.js +28 -5
  284. package/dist/render/renderpass.js.map +1 -1
  285. package/dist/render/sdf/box_allocator.js +98 -0
  286. package/dist/render/sdf/box_allocator.js.map +1 -0
  287. package/dist/render/sdf/global_sdf.js +865 -0
  288. package/dist/render/sdf/global_sdf.js.map +1 -0
  289. package/dist/render/sdf/scene_sdf.js +562 -0
  290. package/dist/render/sdf/scene_sdf.js.map +1 -0
  291. package/dist/render/sdf/sdf_atlas.js +227 -0
  292. package/dist/render/sdf/sdf_atlas.js.map +1 -0
  293. package/dist/render/sdf/sdf_programs.js +42 -0
  294. package/dist/render/sdf/sdf_programs.js.map +1 -0
  295. package/dist/render/sdf/sdf_view.js +199 -0
  296. package/dist/render/sdf/sdf_view.js.map +1 -0
  297. package/dist/render/sdf/waterline.js +610 -0
  298. package/dist/render/sdf/waterline.js.map +1 -0
  299. package/dist/render/shadow_mask_pass.js +142 -25
  300. package/dist/render/shadow_mask_pass.js.map +1 -1
  301. package/dist/render/shore_wave_generator.js +1193 -0
  302. package/dist/render/shore_wave_generator.js.map +1 -0
  303. package/dist/render/sky.js +516 -86
  304. package/dist/render/sky.js.map +1 -1
  305. package/dist/render/transmission_thickness_pass.js +477 -0
  306. package/dist/render/transmission_thickness_pass.js.map +1 -0
  307. package/dist/render/underwater.js +524 -0
  308. package/dist/render/underwater.js.map +1 -0
  309. package/dist/render/virtualtexture/virtual_texture.js +1214 -0
  310. package/dist/render/virtualtexture/virtual_texture.js.map +1 -0
  311. package/dist/render/volumetric_cloud/cloud_common.js +472 -0
  312. package/dist/render/volumetric_cloud/cloud_common.js.map +1 -0
  313. package/dist/render/volumetric_cloud/cloud_noise.js +189 -0
  314. package/dist/render/volumetric_cloud/cloud_noise.js.map +1 -0
  315. package/dist/render/volumetric_cloud/debug_view.js +131 -0
  316. package/dist/render/volumetric_cloud/debug_view.js.map +1 -0
  317. package/dist/render/volumetric_cloud/resources.js +380 -0
  318. package/dist/render/volumetric_cloud/resources.js.map +1 -0
  319. package/dist/render/volumetric_cloud/sky_cache.js +380 -0
  320. package/dist/render/volumetric_cloud/sky_cache.js.map +1 -0
  321. package/dist/render/volumetric_cloud/volumetric_cloud.js +318 -0
  322. package/dist/render/volumetric_cloud/volumetric_cloud.js.map +1 -0
  323. package/dist/render/water_caustics.js +1195 -0
  324. package/dist/render/water_caustics.js.map +1 -0
  325. package/dist/render/water_foam.js +627 -0
  326. package/dist/render/water_foam.js.map +1 -0
  327. package/dist/render/water_interaction.js +1795 -0
  328. package/dist/render/water_interaction.js.map +1 -0
  329. package/dist/render/weightedblended_oit.js +36 -36
  330. package/dist/render/weightedblended_oit.js.map +1 -1
  331. package/dist/scene/basesprite.js +9 -4
  332. package/dist/scene/basesprite.js.map +1 -1
  333. package/dist/scene/batchgroup.js +108 -12
  334. package/dist/scene/batchgroup.js.map +1 -1
  335. package/dist/scene/environment.js +28 -7
  336. package/dist/scene/environment.js.map +1 -1
  337. package/dist/scene/foliage.js +1020 -0
  338. package/dist/scene/foliage.js.map +1 -0
  339. package/dist/scene/foliage_buckets.js +147 -0
  340. package/dist/scene/foliage_buckets.js.map +1 -0
  341. package/dist/scene/foliage_mask.js +358 -0
  342. package/dist/scene/foliage_mask.js.map +1 -0
  343. package/dist/scene/hair.js +15 -4
  344. package/dist/scene/hair.js.map +1 -1
  345. package/dist/scene/light.js +179 -13
  346. package/dist/scene/light.js.map +1 -1
  347. package/dist/scene/mesh.js +327 -45
  348. package/dist/scene/mesh.js.map +1 -1
  349. package/dist/scene/meshdrawable.js +6 -0
  350. package/dist/scene/meshdrawable.js.map +1 -1
  351. package/dist/scene/msdftext.js +9 -3
  352. package/dist/scene/msdftext.js.map +1 -1
  353. package/dist/scene/msdftextsprite.js +9 -3
  354. package/dist/scene/msdftextsprite.js.map +1 -1
  355. package/dist/scene/particlesys.js +8 -2
  356. package/dist/scene/particlesys.js.map +1 -1
  357. package/dist/scene/physics_settings.js +157 -0
  358. package/dist/scene/physics_settings.js.map +1 -0
  359. package/dist/scene/scene.js +190 -44
  360. package/dist/scene/scene.js.map +1 -1
  361. package/dist/scene/scene_node.js +147 -6
  362. package/dist/scene/scene_node.js.map +1 -1
  363. package/dist/scene/terrain-cm/bladegrassmaterial.js +735 -0
  364. package/dist/scene/terrain-cm/bladegrassmaterial.js.map +1 -0
  365. package/dist/scene/terrain-cm/grass.js +881 -42
  366. package/dist/scene/terrain-cm/grass.js.map +1 -1
  367. package/dist/scene/terrain-cm/grass_gpu.js +929 -0
  368. package/dist/scene/terrain-cm/grass_gpu.js.map +1 -0
  369. package/dist/scene/terrain-cm/grassmaterial.js +180 -9
  370. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  371. package/dist/scene/terrain-cm/terrain-cm.js +465 -36
  372. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  373. package/dist/scene/terrain-cm/terrain_gi_albedo.js +257 -0
  374. package/dist/scene/terrain-cm/terrain_gi_albedo.js.map +1 -0
  375. package/dist/scene/terrain-cm/terrain_rvt.js +395 -0
  376. package/dist/scene/terrain-cm/terrain_rvt.js.map +1 -0
  377. package/dist/scene/update_queue.js +54 -0
  378. package/dist/scene/update_queue.js.map +1 -0
  379. package/dist/scene/water.js +997 -96
  380. package/dist/scene/water.js.map +1 -1
  381. package/dist/scene/water_surface_sampler.js +324 -0
  382. package/dist/scene/water_surface_sampler.js.map +1 -0
  383. package/dist/scene/wind.js +317 -0
  384. package/dist/scene/wind.js.map +1 -0
  385. package/dist/shaders/atmosphere.js +388 -166
  386. package/dist/shaders/atmosphere.js.map +1 -1
  387. package/dist/shaders/fog.js +100 -32
  388. package/dist/shaders/fog.js.map +1 -1
  389. package/dist/shaders/gi.js +365 -0
  390. package/dist/shaders/gi.js.map +1 -0
  391. package/dist/shaders/ltc_rect.js +202 -0
  392. package/dist/shaders/ltc_rect.js.map +1 -0
  393. package/dist/shaders/misc.js +1 -10
  394. package/dist/shaders/misc.js.map +1 -1
  395. package/dist/shaders/noise.js +5 -1
  396. package/dist/shaders/noise.js.map +1 -1
  397. package/dist/shaders/probes.js +309 -0
  398. package/dist/shaders/probes.js.map +1 -0
  399. package/dist/shaders/sdf.js +537 -0
  400. package/dist/shaders/sdf.js.map +1 -0
  401. package/dist/shaders/shadow.js +104 -70
  402. package/dist/shaders/shadow.js.map +1 -1
  403. package/dist/shaders/skin_brdf.js +243 -0
  404. package/dist/shaders/skin_brdf.js.map +1 -0
  405. package/dist/shaders/ssr.js +6 -159
  406. package/dist/shaders/ssr.js.map +1 -1
  407. package/dist/shaders/temporal.js +38 -27
  408. package/dist/shaders/temporal.js.map +1 -1
  409. package/dist/shaders/water.js +40 -87
  410. package/dist/shaders/water.js.map +1 -1
  411. package/dist/shaders/water_medium.js +42 -0
  412. package/dist/shaders/water_medium.js.map +1 -0
  413. package/dist/shadow/dom.js +110 -19
  414. package/dist/shadow/dom.js.map +1 -1
  415. package/dist/shadow/esm.js +3 -3
  416. package/dist/shadow/esm.js.map +1 -1
  417. package/dist/shadow/pcf_opt.js +15 -48
  418. package/dist/shadow/pcf_opt.js.map +1 -1
  419. package/dist/shadow/pcf_pd.js +15 -53
  420. package/dist/shadow/pcf_pd.js.map +1 -1
  421. package/dist/shadow/pcss.js +34 -9
  422. package/dist/shadow/pcss.js.map +1 -1
  423. package/dist/shadow/shadow_impl.js +3 -8
  424. package/dist/shadow/shadow_impl.js.map +1 -1
  425. package/dist/shadow/shadow_region.js +87 -49
  426. package/dist/shadow/shadow_region.js.map +1 -1
  427. package/dist/shadow/shadowmapper.js +93 -53
  428. package/dist/shadow/shadowmapper.js.map +1 -1
  429. package/dist/shadow/ssm.js +18 -72
  430. package/dist/shadow/ssm.js.map +1 -1
  431. package/dist/shadow/vsm.js +3 -3
  432. package/dist/shadow/vsm.js.map +1 -1
  433. package/dist/shapes/shape.js +44 -1
  434. package/dist/shapes/shape.js.map +1 -1
  435. package/dist/utility/buoyancy.js +287 -0
  436. package/dist/utility/buoyancy.js.map +1 -0
  437. package/dist/utility/physical.js +10 -1
  438. package/dist/utility/physical.js.map +1 -1
  439. package/dist/utility/pmrem.js +17 -43
  440. package/dist/utility/pmrem.js.map +1 -1
  441. package/dist/utility/sdf/bake.js +435 -0
  442. package/dist/utility/sdf/bake.js.map +1 -0
  443. package/dist/utility/sdf/bvh.js +576 -0
  444. package/dist/utility/sdf/bvh.js.map +1 -0
  445. package/dist/utility/serialization/manager.js +36 -6
  446. package/dist/utility/serialization/manager.js.map +1 -1
  447. package/dist/utility/serialization/scene/animation.js +77 -7
  448. package/dist/utility/serialization/scene/animation.js.map +1 -1
  449. package/dist/utility/serialization/scene/batch.js +11 -4
  450. package/dist/utility/serialization/scene/batch.js.map +1 -1
  451. package/dist/utility/serialization/scene/camera.js +140 -279
  452. package/dist/utility/serialization/scene/camera.js.map +1 -1
  453. package/dist/utility/serialization/scene/cloth.js +25 -0
  454. package/dist/utility/serialization/scene/cloth.js.map +1 -0
  455. package/dist/utility/serialization/scene/common.js +14 -6
  456. package/dist/utility/serialization/scene/common.js.map +1 -1
  457. package/dist/utility/serialization/scene/foliage.js +821 -0
  458. package/dist/utility/serialization/scene/foliage.js.map +1 -0
  459. package/dist/utility/serialization/scene/hair.js +11 -4
  460. package/dist/utility/serialization/scene/hair.js.map +1 -1
  461. package/dist/utility/serialization/scene/light.js +115 -7
  462. package/dist/utility/serialization/scene/light.js.map +1 -1
  463. package/dist/utility/serialization/scene/material.js +388 -220
  464. package/dist/utility/serialization/scene/material.js.map +1 -1
  465. package/dist/utility/serialization/scene/mesh.js +69 -4
  466. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  467. package/dist/utility/serialization/scene/node.js +140 -5
  468. package/dist/utility/serialization/scene/node.js.map +1 -1
  469. package/dist/utility/serialization/scene/node_physics.js +1318 -0
  470. package/dist/utility/serialization/scene/node_physics.js.map +1 -0
  471. package/dist/utility/serialization/scene/particle.js +11 -4
  472. package/dist/utility/serialization/scene/particle.js.map +1 -1
  473. package/dist/utility/serialization/scene/physics.js +120 -0
  474. package/dist/utility/serialization/scene/physics.js.map +1 -0
  475. package/dist/utility/serialization/scene/primitive.js +124 -10
  476. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  477. package/dist/utility/serialization/scene/scene.js +1687 -51
  478. package/dist/utility/serialization/scene/scene.js.map +1 -1
  479. package/dist/utility/serialization/scene/sprite.js +11 -4
  480. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  481. package/dist/utility/serialization/scene/terrain.js +163 -33
  482. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  483. package/dist/utility/serialization/scene/text.js +11 -4
  484. package/dist/utility/serialization/scene/text.js.map +1 -1
  485. package/dist/utility/serialization/scene/water.js +2473 -114
  486. package/dist/utility/serialization/scene/water.js.map +1 -1
  487. package/dist/utility/serialization/types.js.map +1 -1
  488. package/dist/utility/shprojector.js +97 -109
  489. package/dist/utility/shprojector.js.map +1 -1
  490. package/dist/utility/textures/foam.js +170 -0
  491. package/dist/utility/textures/foam.js.map +1 -0
  492. package/dist/utility/textures/ggxlut.js +17 -43
  493. package/dist/utility/textures/ggxlut.js.map +1 -1
  494. package/dist/utility/textures/ltcdata.js +4 -4
  495. package/dist/utility/textures/ltcdata.js.map +1 -1
  496. package/dist/utility/textures/ltclut.js +16 -6
  497. package/dist/utility/textures/ltclut.js.map +1 -1
  498. package/dist/utility/unsupported.js +24 -0
  499. package/dist/utility/unsupported.js.map +1 -0
  500. package/dist/values.js +13 -1
  501. package/dist/values.js.map +1 -1
  502. package/package.json +25 -12
  503. package/src/asset/loaders/ktx2/basis/LICENSE +201 -0
  504. package/src/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  505. package/src/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  506. package/src/asset/meshoptimizer/LICENSE +21 -0
@@ -0,0 +1,1020 @@
1
+ import { Quaternion, Vector3, Matrix4x4, AABB, DRef } from '@zephyr3d/base';
2
+ import { SceneNode } from './scene_node.js';
3
+ import { GraphNode } from './graph_node.js';
4
+ import { BatchGroup } from './batchgroup.js';
5
+ import { Mesh } from './mesh.js';
6
+ import { getEngine } from '../app/api.js';
7
+ import '../physics/part.js';
8
+ import { NodePhysics } from '../physics/node_physics.js';
9
+ import { RigidBody } from '../physics/rigid_body.js';
10
+ import { Collider } from '../physics/collider.js';
11
+ import { FoliageInstanceBuckets, FOLIAGE_INSTANCE_STRIDE } from './foliage_buckets.js';
12
+ import { FoliageDensityMask } from './foliage_mask.js';
13
+ export { FOLIAGE_MASK_TILE_SIZE, foliageBrushWeight } from './foliage_mask.js';
14
+
15
+ function defaultGeneration() {
16
+ return {
17
+ spacing: 4,
18
+ scaleRange: [
19
+ 0.8,
20
+ 1.2
21
+ ],
22
+ slopeRange: [
23
+ 0,
24
+ 45
25
+ ],
26
+ heightRange: null,
27
+ yOffset: 0,
28
+ randomYaw: true,
29
+ seed: Math.floor(Math.random() * 0x7fffffff),
30
+ surface: 'terrain',
31
+ placeScript: ''
32
+ };
33
+ }
34
+ function copyGeneration(g) {
35
+ return {
36
+ ...g,
37
+ scaleRange: [
38
+ g.scaleRange[0],
39
+ g.scaleRange[1]
40
+ ],
41
+ slopeRange: [
42
+ g.slopeRange[0],
43
+ g.slopeRange[1]
44
+ ],
45
+ heightRange: g.heightRange ? [
46
+ g.heightRange[0],
47
+ g.heightRange[1]
48
+ ] : null
49
+ };
50
+ }
51
+ /** A generation setting with the omitted and invalid fields of `g` taken from `base` */ function mergeGeneration(base, g) {
52
+ const num = (v, d)=>typeof v === 'number' && Number.isFinite(v) ? v : d;
53
+ const pair = (v, d)=>Array.isArray(v) && v.length === 2 ? [
54
+ num(v[0], d[0]),
55
+ num(v[1], d[1])
56
+ ] : [
57
+ d[0],
58
+ d[1]
59
+ ];
60
+ return {
61
+ spacing: Math.max(0.05, num(g.spacing, base.spacing)),
62
+ scaleRange: pair(g.scaleRange, base.scaleRange),
63
+ slopeRange: pair(g.slopeRange, base.slopeRange),
64
+ heightRange: g.heightRange === undefined ? base.heightRange ? [
65
+ base.heightRange[0],
66
+ base.heightRange[1]
67
+ ] : null : g.heightRange ? pair(g.heightRange, [
68
+ -Infinity,
69
+ Infinity
70
+ ]) : null,
71
+ yOffset: num(g.yOffset, base.yOffset),
72
+ randomYaw: typeof g.randomYaw === 'boolean' ? g.randomYaw : base.randomYaw,
73
+ seed: Math.floor(num(g.seed, base.seed)) | 0,
74
+ surface: g.surface === 'terrain' || g.surface === 'any' ? g.surface : base.surface,
75
+ placeScript: typeof g.placeScript === 'string' ? g.placeScript : base.placeScript
76
+ };
77
+ }
78
+ const PRIMITIVE_COLLIDER_SHAPES = [
79
+ 'box',
80
+ 'sphere',
81
+ 'capsule',
82
+ 'cylinder'
83
+ ];
84
+ /**
85
+ * One kind of object scattered by a {@link FoliageSystem}: an asset and where its copies stand.
86
+ *
87
+ * @remarks
88
+ * A layer holds two groups of instances. The generated ones follow from its
89
+ * {@link FoliageLayer.mask | density mask} and {@link FoliageLayer.generation | generation
90
+ * settings}, and only painting and regenerating change them. The manual ones are placed
91
+ * directly and are left alone by generation; only erasing and the instance methods remove them.
92
+ * Both are drawn and collide alike.
93
+ * @public
94
+ */ class FoliageLayer {
95
+ /** The foliage system the layer belongs to @internal */ _owner;
96
+ /** @internal */ _asset;
97
+ /** @internal */ _generated;
98
+ /** @internal */ _manual;
99
+ /** @internal */ _mask;
100
+ /** @internal */ _generation;
101
+ /** @internal */ _castShadow;
102
+ /** @internal */ _cullDistance;
103
+ /** @internal */ _alignToNormal;
104
+ /** @internal */ _collision;
105
+ /** @internal */ _parts;
106
+ /** Bounds of the asset's meshes, relative to its root @internal */ _bounds;
107
+ /** Colliders found on the asset's nodes @internal */ _assetColliders;
108
+ /** @internal */ _loading;
109
+ /**
110
+ * Creates a layer; add it to a foliage system with {@link FoliageSystem.insertLayer}
111
+ * @param asset - Path of the prefab or model asset the layer scatters
112
+ * @param settings - Layer settings
113
+ */ constructor(asset = '', settings){
114
+ this._owner = null;
115
+ this._asset = asset;
116
+ this._generated = new FoliageInstanceBuckets(64);
117
+ this._manual = new FoliageInstanceBuckets(64);
118
+ this._mask = new FoliageDensityMask(1);
119
+ this._generation = mergeGeneration(defaultGeneration(), settings?.generation ?? {});
120
+ this._castShadow = settings?.castShadow ?? true;
121
+ this._cullDistance = settings?.cullDistance ?? 300;
122
+ this._alignToNormal = settings?.alignToNormal ?? 0;
123
+ this._collision = copyCollision(settings?.collision);
124
+ this._parts = null;
125
+ this._bounds = null;
126
+ this._assetColliders = [];
127
+ this._loading = null;
128
+ }
129
+ /** The foliage system the layer belongs to */ get owner() {
130
+ return this._owner;
131
+ }
132
+ /** Path of the prefab or model asset the layer scatters; changing it keeps the instances */ get asset() {
133
+ return this._asset;
134
+ }
135
+ set asset(val) {
136
+ if (val !== this._asset) {
137
+ this._dispose();
138
+ this._asset = val;
139
+ this._owner?.invalidate();
140
+ }
141
+ }
142
+ /** Number of instances of both groups */ get count() {
143
+ return this._generated.count + this._manual.count;
144
+ }
145
+ /** Number of instances generated from the density mask */ get generatedCount() {
146
+ return this._generated.count;
147
+ }
148
+ /** Number of instances placed directly */ get manualCount() {
149
+ return this._manual.count;
150
+ }
151
+ /**
152
+ * Where the layer grows when painted. Change it through the foliage brush or
153
+ * {@link FoliageSystem.paintMask}, which keep the generated instances in step.
154
+ */ get mask() {
155
+ return this._mask;
156
+ }
157
+ /**
158
+ * How painted instances are generated. Reading gives a copy; assigning one changes the
159
+ * settings but not the instances, until the layer is regenerated.
160
+ */ get generation() {
161
+ return copyGeneration(this._generation);
162
+ }
163
+ set generation(val) {
164
+ this._generation = mergeGeneration(this._generation, val);
165
+ }
166
+ /** Whether the instances cast shadows */ get castShadow() {
167
+ return this._castShadow;
168
+ }
169
+ set castShadow(val) {
170
+ if (val !== this._castShadow) {
171
+ this._castShadow = val;
172
+ this._owner?.invalidate();
173
+ }
174
+ }
175
+ /** Distance from the camera beyond which the instances are not drawn */ get cullDistance() {
176
+ return this._cullDistance;
177
+ }
178
+ set cullDistance(val) {
179
+ // Only decides which chunks are shown each frame, nothing to rebuild
180
+ this._cullDistance = val;
181
+ }
182
+ /** How much the instances lean with the ground: 0 stays upright, 1 follows the normal */ get alignToNormal() {
183
+ return this._alignToNormal;
184
+ }
185
+ set alignToNormal(val) {
186
+ if (val !== this._alignToNormal) {
187
+ this._alignToNormal = val;
188
+ this._owner?.invalidate();
189
+ }
190
+ }
191
+ /** What the instances collide with; null for nothing. Reading gives a copy; assign to change it. */ get collision() {
192
+ return copyCollision(this._collision);
193
+ }
194
+ set collision(val) {
195
+ this._collision = copyCollision(val);
196
+ this._owner?.invalidate();
197
+ }
198
+ /** @internal */ _colliderTemplates() {
199
+ const c = this._collision;
200
+ if (!c) {
201
+ return [];
202
+ }
203
+ if (c.shape === 'asset') {
204
+ return this._assetColliders;
205
+ }
206
+ const b = this._bounds;
207
+ const ext = b ? Vector3.sub(b.maxPoint, b.minPoint) : new Vector3(1, 1, 1);
208
+ const center = b ? Vector3.scale(Vector3.add(b.minPoint, b.maxPoint), 0.5) : new Vector3(0, 0.5, 0);
209
+ const bottom = b ? b.minPoint.y : 0;
210
+ const height = c.height ?? ext.y;
211
+ const radius = c.radius ?? (c.shape === 'sphere' ? Math.max(ext.x, ext.y, ext.z) : Math.min(ext.x, ext.z)) / 2;
212
+ const offset = c.offset ? new Vector3(c.offset[0], c.offset[1], c.offset[2]) : c.shape === 'capsule' || c.shape === 'cylinder' ? new Vector3(0, bottom + height / 2, 0) : center;
213
+ return [
214
+ {
215
+ matrix: Matrix4x4.identity(),
216
+ shape: c.shape,
217
+ size: c.size ? new Vector3(c.size[0], c.size[1], c.size[2]) : ext,
218
+ radius,
219
+ height,
220
+ offset,
221
+ friction: c.friction ?? 0.5,
222
+ restitution: c.restitution ?? 0,
223
+ layer: c.layer ?? 0
224
+ }
225
+ ];
226
+ }
227
+ /**
228
+ * The instances, {@link FOLIAGE_INSTANCE_STRIDE} floats each: x, z (local to the foliage system),
229
+ * height offset above the ground, rotation about the vertical axis in radians, uniform scale.
230
+ * A copy: change instances with the methods of {@link FoliageSystem}.
231
+ * @param group - Which instances; both groups by default, the manual ones first
232
+ */ getInstances(group = 'all') {
233
+ if (group === 'generated') {
234
+ return this._generated.toArray();
235
+ }
236
+ if (group === 'manual') {
237
+ return this._manual.toArray();
238
+ }
239
+ const manual = this._manual.toArray();
240
+ const generated = this._generated.toArray();
241
+ const out = new Float32Array(manual.length + generated.length);
242
+ out.set(manual);
243
+ out.set(generated, manual.length);
244
+ return out;
245
+ }
246
+ /** @internal */ _dispose() {
247
+ for (const part of this._parts ?? []){
248
+ part.primitive.dispose();
249
+ part.material.dispose();
250
+ }
251
+ this._parts = null;
252
+ this._bounds = null;
253
+ this._assetColliders = [];
254
+ // A load still running is for the old asset, it discards its result
255
+ this._loading = null;
256
+ }
257
+ }
258
+ const COLLISION_SHAPES = [
259
+ 'box',
260
+ 'sphere',
261
+ 'capsule',
262
+ 'cylinder',
263
+ 'asset'
264
+ ];
265
+ /** A copy of a collision setting; null for none, or for one without a valid shape */ function copyCollision(c) {
266
+ if (!c || !COLLISION_SHAPES.includes(c.shape)) {
267
+ return null;
268
+ }
269
+ return {
270
+ ...c,
271
+ size: c.size ? [
272
+ c.size[0],
273
+ c.size[1],
274
+ c.size[2]
275
+ ] : undefined,
276
+ offset: c.offset ? [
277
+ c.offset[0],
278
+ c.offset[1],
279
+ c.offset[2]
280
+ ] : undefined
281
+ };
282
+ }
283
+ /** Deterministic value in [0, 1) from a position, standing in for the threshold of a manual instance */ function positionHash(x, z) {
284
+ const f = new Float32Array([
285
+ x,
286
+ z
287
+ ]);
288
+ const u = new Uint32Array(f.buffer);
289
+ let h = Math.imul(u[0] ^ 0x9e3779b9, 0x85ebca6b) ^ Math.imul(u[1] ^ 0x7f4a7c15, 0xc2b2ae35);
290
+ h ^= h >>> 16;
291
+ h = Math.imul(h, 0x7feb352d);
292
+ h ^= h >>> 15;
293
+ h = Math.imul(h, 0x846ca68b);
294
+ h ^= h >>> 16;
295
+ return (h >>> 0) / 4294967296;
296
+ }
297
+ const tmpQuat = new Quaternion();
298
+ const tmpAlign = new Quaternion();
299
+ const tmpNormal = new Vector3();
300
+ const tmpScale = new Vector3();
301
+ const tmpPos = new Vector3();
302
+ const tmpMatrix = new Matrix4x4();
303
+ const tmpMatrix2 = new Matrix4x4();
304
+ const UP = Vector3.axisPY();
305
+ /**
306
+ * Scatters many copies of prefabs or models, such as trees, bushes and rocks, over a terrain.
307
+ *
308
+ * @remarks
309
+ * Each {@link FoliageLayer} scatters one asset. An instance stores only its horizontal position,
310
+ * an offset above the ground, a rotation about the vertical axis and a scale; its height is taken
311
+ * from the {@link ClipmapTerrain} the system is a descendant of, so the instances follow the
312
+ * ground when the terrain changes. Without a terrain ancestor the offset is the height.
313
+ *
314
+ * Instances are drawn in square chunks of {@link FoliageSystem.chunkSize}, each a
315
+ * {@link BatchGroup} built on demand and not serialized, which draws a whole chunk in a few
316
+ * instanced draw calls; chunks farther than the cull distance of their layer are hidden.
317
+ * Changing the instances of an area rebuilds only the chunks it overlaps.
318
+ *
319
+ * Positions are in the space of the foliage system, which is meant to be translated only.
320
+ * @public
321
+ */ class FoliageSystem extends GraphNode {
322
+ _layers;
323
+ _chunkSize;
324
+ _maskCellSize;
325
+ _chunks;
326
+ _dirty;
327
+ _dirtyChunks;
328
+ _buildSerial;
329
+ _builtHeightData;
330
+ _builtTerrain;
331
+ /**
332
+ * Creates a foliage system
333
+ * @param scene - The scene to which the node belongs
334
+ */ constructor(scene){
335
+ super(scene);
336
+ this._layers = [];
337
+ this._chunkSize = 64;
338
+ this._maskCellSize = 1;
339
+ this._chunks = new Map();
340
+ this._dirty = false;
341
+ this._dirtyChunks = new Map();
342
+ this._buildSerial = 0;
343
+ this._builtHeightData = null;
344
+ this._builtTerrain = null;
345
+ }
346
+ /** Edge length of the square chunks the instances are drawn in. Default 64. */ get chunkSize() {
347
+ return this._chunkSize;
348
+ }
349
+ set chunkSize(val) {
350
+ val = Math.max(1, val);
351
+ if (val !== this._chunkSize) {
352
+ this._chunkSize = val;
353
+ for (const layer of this._layers){
354
+ layer._generated.setChunkSize(val);
355
+ layer._manual.setChunkSize(val);
356
+ }
357
+ this.invalidate();
358
+ }
359
+ }
360
+ /**
361
+ * Edge of a cell of the density masks of the layers, in meters. Default 1. Changing it keeps
362
+ * the cell values, so what was painted scales with it; regenerate the layers afterwards.
363
+ */ get maskCellSize() {
364
+ return this._maskCellSize;
365
+ }
366
+ set maskCellSize(val) {
367
+ val = Math.max(0.05, val);
368
+ if (val !== this._maskCellSize) {
369
+ this._maskCellSize = val;
370
+ for (const layer of this._layers){
371
+ layer._mask.cellSize = val;
372
+ }
373
+ }
374
+ }
375
+ /** Number of layers */ get numLayers() {
376
+ return this._layers.length;
377
+ }
378
+ /** Total number of instances of all layers */ get numInstances() {
379
+ return this._layers.reduce((sum, layer)=>sum + layer.count, 0);
380
+ }
381
+ /**
382
+ * Gets a layer
383
+ * @param index - Layer index
384
+ */ getLayer(index) {
385
+ return this._layers[index] ?? null;
386
+ }
387
+ /**
388
+ * Index of a layer of this system
389
+ * @param layer - The layer
390
+ * @returns Its index, or -1
391
+ */ indexOfLayer(layer) {
392
+ return this._layers.indexOf(layer);
393
+ }
394
+ /**
395
+ * Adds a layer scattering a prefab (.zprefab) or a model asset
396
+ * @param asset - Path of the asset
397
+ * @param settings - Layer settings
398
+ * @returns Index of the new layer
399
+ */ addLayer(asset, settings) {
400
+ return this.insertLayer(new FoliageLayer(asset, settings));
401
+ }
402
+ /**
403
+ * Inserts a layer, which is moved out of the foliage system it belongs to
404
+ * @param layer - The layer
405
+ * @param index - Position to insert at; appended when omitted
406
+ * @returns Index of the layer
407
+ */ insertLayer(layer, index) {
408
+ if (layer._owner) {
409
+ layer._owner.detachLayer(layer);
410
+ }
411
+ const at = Math.max(0, Math.min(index ?? this._layers.length, this._layers.length));
412
+ this._layers.splice(at, 0, layer);
413
+ this.adoptLayer(layer);
414
+ this.invalidate();
415
+ return at;
416
+ }
417
+ /**
418
+ * Removes a layer and its instances
419
+ * @param index - Layer index
420
+ */ removeLayer(index) {
421
+ const layer = this._layers[index];
422
+ if (layer) {
423
+ this.detachLayer(layer);
424
+ layer._dispose();
425
+ }
426
+ }
427
+ /**
428
+ * Removes every layer
429
+ */ clearLayers() {
430
+ for (const layer of this._layers){
431
+ layer._owner = null;
432
+ layer._dispose();
433
+ }
434
+ this._layers = [];
435
+ this.invalidate();
436
+ }
437
+ /**
438
+ * Replaces the layer list. Layers already in the system keep their loaded assets, layers
439
+ * left out are disposed, and layers of another system are moved here.
440
+ * @param layers - The new layers, in order
441
+ */ setLayers(layers) {
442
+ const next = layers.filter((layer, i)=>layers.indexOf(layer) === i);
443
+ for (const layer of this._layers){
444
+ if (!next.includes(layer)) {
445
+ layer._owner = null;
446
+ layer._dispose();
447
+ }
448
+ }
449
+ for (const layer of next){
450
+ if (layer._owner && layer._owner !== this) {
451
+ layer._owner.detachLayer(layer);
452
+ }
453
+ this.adoptLayer(layer);
454
+ }
455
+ this._layers = next;
456
+ this.invalidate();
457
+ }
458
+ /** Makes a layer use this system's chunk and mask cell sizes */ adoptLayer(layer) {
459
+ layer._owner = this;
460
+ layer._generated.setChunkSize(this._chunkSize);
461
+ layer._manual.setChunkSize(this._chunkSize);
462
+ layer._mask.cellSize = this._maskCellSize;
463
+ }
464
+ /** Takes a layer out of the list, keeping its instances */ detachLayer(layer) {
465
+ const index = this._layers.indexOf(layer);
466
+ if (index >= 0) {
467
+ this._layers.splice(index, 1);
468
+ layer._owner = null;
469
+ this.invalidate();
470
+ }
471
+ }
472
+ /**
473
+ * Changes the settings of a layer
474
+ * @param index - Layer index
475
+ * @param settings - Settings to change; omitted ones are kept
476
+ */ setLayerSettings(index, settings) {
477
+ const layer = this._layers[index];
478
+ if (!layer) {
479
+ return;
480
+ }
481
+ if (settings.asset !== undefined) {
482
+ layer.asset = settings.asset;
483
+ }
484
+ layer._castShadow = settings.castShadow ?? layer._castShadow;
485
+ layer._cullDistance = settings.cullDistance ?? layer._cullDistance;
486
+ layer._alignToNormal = settings.alignToNormal ?? layer._alignToNormal;
487
+ if (settings.collision !== undefined) {
488
+ layer._collision = copyCollision(settings.collision);
489
+ }
490
+ if (settings.generation) {
491
+ layer._generation = mergeGeneration(layer._generation, settings.generation);
492
+ }
493
+ this.invalidate();
494
+ }
495
+ /**
496
+ * Replaces the instances of a layer of one group
497
+ * @param index - Layer index
498
+ * @param data - {@link FOLIAGE_INSTANCE_STRIDE} floats per instance, see {@link FoliageLayer.getInstances}
499
+ * @param group - Which instances to replace. Default 'manual'; 'all' empties the generated
500
+ * group and puts the instances in the manual one.
501
+ */ setInstances(index, data, group = 'manual') {
502
+ const layer = this._layers[index];
503
+ if (!layer) {
504
+ return;
505
+ }
506
+ const touched = new Set();
507
+ if (group === 'generated') {
508
+ for (const key of layer._generated.clear()){
509
+ touched.add(key);
510
+ }
511
+ layer._generated.add(data, touched);
512
+ } else {
513
+ if (group === 'all') {
514
+ for (const key of layer._generated.clear()){
515
+ touched.add(key);
516
+ }
517
+ }
518
+ for (const key of layer._manual.clear()){
519
+ touched.add(key);
520
+ }
521
+ layer._manual.add(data, touched);
522
+ }
523
+ this.invalidateChunks(layer, touched);
524
+ }
525
+ /**
526
+ * Appends instances to a layer
527
+ * @param index - Layer index
528
+ * @param data - {@link FOLIAGE_INSTANCE_STRIDE} floats per instance, see {@link FoliageLayer.getInstances}
529
+ * @param group - Which group receives them. Default 'manual'.
530
+ */ addInstances(index, data, group = 'manual') {
531
+ const layer = this._layers[index];
532
+ if (!layer) {
533
+ return;
534
+ }
535
+ const touched = new Set();
536
+ (group === 'generated' ? layer._generated : layer._manual).add(data, touched);
537
+ this.invalidateChunks(layer, touched);
538
+ }
539
+ /**
540
+ * Replaces the generated instances of a layer standing within a region
541
+ *
542
+ * @remarks
543
+ * Used by the foliage generator: the region is aligned with the candidate grid, so the
544
+ * instances removed and the ones added are of the same candidates.
545
+ * @param index - Layer index
546
+ * @param region - `[minX, minZ, maxX, maxZ]`, local; instances with minX ≤ x < maxX and
547
+ * minZ ≤ z < maxZ are replaced
548
+ * @param data - The new instances of the region
549
+ */ replaceGeneratedInRegion(index, region, data) {
550
+ const layer = this._layers[index];
551
+ if (!layer) {
552
+ return;
553
+ }
554
+ const touched = new Set();
555
+ layer._generated.removeWhere(region, (d, o)=>d[o] >= region[0] && d[o] < region[2] && d[o + 1] >= region[1] && d[o + 1] < region[3], touched);
556
+ layer._generated.add(data, touched);
557
+ this.invalidateChunks(layer, touched);
558
+ }
559
+ /**
560
+ * Changes the density mask of a layer within a circle; the generated instances are not
561
+ * regenerated, see {@link FoliageLayer.mask}
562
+ * @param index - Layer index
563
+ * @param x - Circle centre x, local
564
+ * @param z - Circle centre z, local
565
+ * @param radius - Circle radius
566
+ * @param amount - Change at full weight, -1 to 1; negative erases
567
+ * @param falloff - Fraction of the radius over which the brush weight falls to 0
568
+ * @returns The changed region, or null
569
+ */ paintMask(index, x, z, radius, amount, falloff = 0.5) {
570
+ return this._layers[index]?._mask.paintCircle(x, z, radius, amount, falloff) ?? null;
571
+ }
572
+ /**
573
+ * Moves the density mask of a layer within a circle towards a density; the generated
574
+ * instances are not regenerated, see {@link FoliageLayer.mask}
575
+ * @param index - Layer index
576
+ * @param x - Circle centre x, local
577
+ * @param z - Circle centre z, local
578
+ * @param radius - Circle radius
579
+ * @param density - Density inside the circle, 0 to 1
580
+ * @param falloff - Fraction of the radius over which it blends into what is around
581
+ * @returns The changed region, or null
582
+ */ fillMaskCircle(index, x, z, radius, density, falloff = 0.5) {
583
+ return this._layers[index]?._mask.blendCircle(x, z, radius, density, falloff) ?? null;
584
+ }
585
+ /**
586
+ * Erases manual instances within a circle, by brush weight: an instance goes where the weight
587
+ * of the brush there is above a value derived from its position, so a soft brush thins them
588
+ * out towards its edge, the same way every time
589
+ * @param index - Layer index
590
+ * @param x - Circle centre x, local
591
+ * @param z - Circle centre z, local
592
+ * @param radius - Circle radius
593
+ * @param strength - Weight at the centre, 0 to 1
594
+ * @param weight - Brush weight from the distance over the radius
595
+ * @returns Number of instances removed
596
+ */ eraseManualInstances(index, x, z, radius, strength, weight) {
597
+ const layer = this._layers[index];
598
+ if (!layer || !(radius > 0) || !(strength > 0)) {
599
+ return 0;
600
+ }
601
+ const touched = new Set();
602
+ const removed = layer._manual.removeWhere([
603
+ x - radius,
604
+ z - radius,
605
+ x + radius,
606
+ z + radius
607
+ ], (d, o)=>{
608
+ const t = Math.hypot(d[o] - x, d[o + 1] - z) / radius;
609
+ return t < 1 && strength * weight(t) > positionHash(d[o], d[o + 1]);
610
+ }, touched);
611
+ this.invalidateChunks(layer, touched);
612
+ return removed;
613
+ }
614
+ /**
615
+ * Removes the instances standing within a circle
616
+ *
617
+ * @remarks
618
+ * Generated instances are removed by clearing the density mask under the circle, so
619
+ * regenerating the layer does not bring them back.
620
+ * @param x - Circle centre x, local to the foliage system
621
+ * @param z - Circle centre z, local to the foliage system
622
+ * @param radius - Circle radius
623
+ * @param index - Layer index, or -1 for every layer
624
+ * @param group - Which instances. Default 'all'.
625
+ * @returns Number of instances removed
626
+ */ removeInstancesInCircle(x, z, radius, index = -1, group = 'all') {
627
+ let removed = 0;
628
+ const r2 = radius * radius;
629
+ const region = [
630
+ x - radius,
631
+ z - radius,
632
+ x + radius,
633
+ z + radius
634
+ ];
635
+ const inside = (d, o)=>{
636
+ const dx = d[o] - x;
637
+ const dz = d[o + 1] - z;
638
+ return dx * dx + dz * dz <= r2;
639
+ };
640
+ this._layers.forEach((layer, i)=>{
641
+ if (index >= 0 && i !== index) {
642
+ return;
643
+ }
644
+ const touched = new Set();
645
+ if (group !== 'generated') {
646
+ removed += layer._manual.removeWhere(region, inside, touched);
647
+ }
648
+ if (group !== 'manual') {
649
+ layer._mask.fillCircle(x, z, radius, 0);
650
+ removed += layer._generated.removeWhere(region, inside, touched);
651
+ }
652
+ this.invalidateChunks(layer, touched);
653
+ });
654
+ return removed;
655
+ }
656
+ /**
657
+ * The terrain the instances stand on: the closest {@link ClipmapTerrain} ancestor
658
+ */ get terrain() {
659
+ let node = this.parent;
660
+ while(node){
661
+ if (node.isClipmapTerrain()) {
662
+ return node;
663
+ }
664
+ node = node.parent;
665
+ }
666
+ return null;
667
+ }
668
+ /**
669
+ * Schedules every chunk to be rebuilt; called by the methods changing layers
670
+ */ invalidate() {
671
+ this._dirty = true;
672
+ // Also called while the base constructor attaches the node, before the fields exist
673
+ this._dirtyChunks?.clear();
674
+ this.scene?.queuePerCameraUpdateNode(this);
675
+ }
676
+ /** Schedules some chunks of a layer to be rebuilt */ invalidateChunks(layer, keys) {
677
+ if (this._dirty) {
678
+ return;
679
+ }
680
+ let set = this._dirtyChunks.get(layer);
681
+ for (const key of keys){
682
+ if (!set) {
683
+ set = new Set();
684
+ this._dirtyChunks.set(layer, set);
685
+ }
686
+ set.add(key);
687
+ }
688
+ if (set) {
689
+ this.scene?.queuePerCameraUpdateNode(this);
690
+ }
691
+ }
692
+ /** {@inheritDoc SceneNode.updatePerCamera} */ updatePerCamera(camera, _elapsedInSeconds, _deltaInSeconds) {
693
+ this.scene?.queuePerCameraUpdateNode(this);
694
+ const terrain = this.terrain;
695
+ // Rebuilt once the terrain heights the instances stand on are known again after a change
696
+ if (terrain !== this._builtTerrain || terrain && terrain.heightData !== this._builtHeightData) {
697
+ if (!terrain || terrain.heightData) {
698
+ this._dirty = true;
699
+ } else {
700
+ terrain.whenHeightDataReady();
701
+ }
702
+ }
703
+ if (this._dirty) {
704
+ this._dirty = false;
705
+ this._dirtyChunks.clear();
706
+ this.rebuild();
707
+ } else if (this._dirtyChunks.size > 0) {
708
+ this.rebuildChunks();
709
+ }
710
+ const eye = camera.getWorldPosition();
711
+ const ox = this.worldMatrix.m03;
712
+ const oz = this.worldMatrix.m23;
713
+ const ex = eye.x - ox;
714
+ const ez = eye.z - oz;
715
+ for (const chunks of this._chunks.values()){
716
+ for (const chunk of chunks.values()){
717
+ const dx = Math.max(chunk.minX - ex, 0, ex - chunk.maxX);
718
+ const dz = Math.max(chunk.minZ - ez, 0, ez - chunk.maxZ);
719
+ const visible = dx * dx + dz * dz <= chunk.layer._cullDistance * chunk.layer._cullDistance;
720
+ if (visible !== chunk.visible) {
721
+ chunk.visible = visible;
722
+ chunk.group.showState = visible ? 'inherit' : 'hidden';
723
+ }
724
+ }
725
+ }
726
+ }
727
+ /** @internal */ _onAttached() {
728
+ super._onAttached();
729
+ this.invalidate();
730
+ }
731
+ /** Rebuilds every chunk, loading the layer assets first */ rebuild() {
732
+ const serial = ++this._buildSerial;
733
+ const terrain = this.terrain;
734
+ const heightData = terrain?.heightData ?? null;
735
+ const pending = this._layers.filter((layer)=>!layer._parts).map((layer)=>this.loadLayer(layer));
736
+ Promise.all(pending).then(()=>{
737
+ if (serial !== this._buildSerial || this.disposed) {
738
+ return;
739
+ }
740
+ this.clearChunks();
741
+ this._builtTerrain = terrain;
742
+ this._builtHeightData = heightData;
743
+ for (const layer of this._layers){
744
+ for (const key of new Set([
745
+ ...layer._generated.keys(),
746
+ ...layer._manual.keys()
747
+ ])){
748
+ this.buildChunk(layer, key, terrain);
749
+ }
750
+ }
751
+ });
752
+ }
753
+ /** Rebuilds the chunks marked dirty, once every layer is loaded */ rebuildChunks() {
754
+ if (this._layers.some((layer)=>!layer._parts)) {
755
+ // A layer still loading: its full rebuild picks the changes up
756
+ this._dirty = true;
757
+ return;
758
+ }
759
+ const terrain = this._builtTerrain;
760
+ for (const [layer, keys] of this._dirtyChunks){
761
+ if (!this._layers.includes(layer)) {
762
+ continue;
763
+ }
764
+ for (const key of keys){
765
+ this.disposeChunk(layer, key);
766
+ this.buildChunk(layer, key, terrain);
767
+ }
768
+ }
769
+ this._dirtyChunks.clear();
770
+ }
771
+ clearChunks() {
772
+ for (const chunks of this._chunks.values()){
773
+ for (const chunk of chunks.values()){
774
+ chunk.group.remove();
775
+ chunk.group.dispose();
776
+ chunk.colliders?.dispose();
777
+ }
778
+ }
779
+ this._chunks.clear();
780
+ }
781
+ disposeChunk(layer, key) {
782
+ const chunks = this._chunks.get(layer);
783
+ const chunk = chunks?.get(key);
784
+ if (chunk) {
785
+ chunk.group.remove();
786
+ chunk.group.dispose();
787
+ chunk.colliders?.dispose();
788
+ chunks.delete(key);
789
+ }
790
+ }
791
+ loadLayer(layer) {
792
+ if (!layer._asset) {
793
+ // A layer just added in the editor, nothing to draw until an asset is picked
794
+ layer._parts = [];
795
+ return Promise.resolve();
796
+ }
797
+ if (!layer._loading) {
798
+ const asset = layer._asset;
799
+ layer._loading = (async ()=>{
800
+ const scene = this.scene;
801
+ const tmp = new SceneNode(scene);
802
+ tmp.remove();
803
+ let root = null;
804
+ try {
805
+ const manager = getEngine().resourceManager;
806
+ root = asset.toLowerCase().endsWith('.zprefab') ? await manager.instantiatePrefab(tmp, asset) : await manager.fetchModel(asset, scene) ?? null;
807
+ if (root) {
808
+ root.parent = tmp;
809
+ root.position.setXYZ(0, 0, 0);
810
+ root.rotation.identity();
811
+ root.scale.setXYZ(1, 1, 1);
812
+ }
813
+ } catch (err) {
814
+ console.error(`Foliage: cannot load ${asset}: ${err}`);
815
+ }
816
+ const parts = [];
817
+ const colliders = [];
818
+ let bounds = null;
819
+ root?.iterate((node)=>{
820
+ for (const c of node.physics?.colliders ?? []){
821
+ if (PRIMITIVE_COLLIDER_SHAPES.includes(c.shape)) {
822
+ colliders.push({
823
+ matrix: new Matrix4x4(node.worldMatrix),
824
+ shape: c.shape,
825
+ size: new Vector3(c.size),
826
+ radius: c.radius,
827
+ height: c.height,
828
+ offset: new Vector3(c.offset),
829
+ friction: c.friction,
830
+ restitution: c.restitution,
831
+ layer: c.layer
832
+ });
833
+ } else {
834
+ console.warn(`Foliage: ${c.shape} colliders of ${asset} are skipped`);
835
+ }
836
+ }
837
+ if (node.isMesh() && node.primitive && node.material) {
838
+ const box = node.primitive.getBoundingVolume()?.toAABB();
839
+ if (box) {
840
+ const world = AABB.transform(box, node.worldMatrix);
841
+ if (bounds) {
842
+ bounds.union(world);
843
+ } else {
844
+ bounds = world;
845
+ }
846
+ }
847
+ if (node.skeletonName || node.morphTargetGroups?.length) {
848
+ console.warn(`Foliage: skinned and morphed meshes of ${asset} are skipped`);
849
+ return false;
850
+ }
851
+ const material = node.material;
852
+ parts.push({
853
+ primitive: new DRef(node.primitive),
854
+ // Instance materials are what lets the copies of a mesh be drawn instanced
855
+ material: new DRef(material.$isInstance ? material : material.createInstance()),
856
+ matrix: new Matrix4x4(node.worldMatrix)
857
+ });
858
+ }
859
+ return false;
860
+ });
861
+ tmp.dispose();
862
+ if (layer._asset !== asset) {
863
+ // The asset changed while loading: the meshes are of the old one
864
+ for (const part of parts){
865
+ part.primitive.dispose();
866
+ part.material.dispose();
867
+ }
868
+ return;
869
+ }
870
+ if (parts.length === 0) {
871
+ console.error(`Foliage: ${asset} has no mesh to scatter`);
872
+ }
873
+ layer._parts = parts;
874
+ layer._bounds = bounds;
875
+ layer._assetColliders = colliders;
876
+ layer._loading = null;
877
+ })();
878
+ }
879
+ return layer._loading;
880
+ }
881
+ /** Builds the batch group and colliders of one chunk of a layer, from both instance groups */ buildChunk(layer, key, terrain) {
882
+ const parts = layer._parts;
883
+ if (!parts || parts.length === 0) {
884
+ return;
885
+ }
886
+ const sources = [
887
+ layer._manual.get(key),
888
+ layer._generated.get(key)
889
+ ].filter((d)=>!!d && d.length > 0);
890
+ if (sources.length === 0) {
891
+ return;
892
+ }
893
+ const size = this._chunkSize;
894
+ const [cx, cz] = key.split(',').map(Number);
895
+ const ox = this.worldMatrix.m03;
896
+ const oy = this.worldMatrix.m13;
897
+ const oz = this.worldMatrix.m23;
898
+ const templates = layer._colliderTemplates();
899
+ // Painted instances on any surface store their height; the others stand on the terrain
900
+ const onTerrain = (generated)=>!generated || layer._generation.surface === 'terrain';
901
+ const group = new BatchGroup(this.scene);
902
+ group.sealed = true;
903
+ group.name = `Foliage chunk ${cx},${cz}`;
904
+ group.parent = this;
905
+ // One static body per chunk, with a collider node per instance and template
906
+ let colliders = null;
907
+ if (templates.length > 0) {
908
+ colliders = new SceneNode(this.scene);
909
+ colliders.sealed = true;
910
+ colliders.name = `Foliage colliders ${cx},${cz}`;
911
+ colliders.parent = this;
912
+ const body = new RigidBody();
913
+ body.motionType = 'static';
914
+ colliders.physics = new NodePhysics({
915
+ body
916
+ });
917
+ }
918
+ const manual = layer._manual.get(key);
919
+ for (const d of sources){
920
+ const followTerrain = onTerrain(d !== manual);
921
+ for(let o = 0; o < d.length; o += FOLIAGE_INSTANCE_STRIDE){
922
+ const x = d[o];
923
+ const z = d[o + 1];
924
+ let y = d[o + 2];
925
+ let upright = true;
926
+ if (terrain && followTerrain) {
927
+ const h = terrain.getHeightAt(x + ox, z + oz);
928
+ if (h !== null) {
929
+ y += h - oy;
930
+ if (layer._alignToNormal > 0 && terrain.getNormalAt(x + ox, z + oz, tmpNormal)) {
931
+ Quaternion.unitVectorToUnitVector(UP, tmpNormal, tmpAlign);
932
+ Quaternion.slerp(Quaternion.identity(tmpQuat), tmpAlign, layer._alignToNormal, tmpAlign);
933
+ upright = false;
934
+ }
935
+ }
936
+ }
937
+ Quaternion.fromAxisAngle(UP, d[o + 3], tmpQuat);
938
+ if (!upright) {
939
+ Quaternion.multiply(tmpAlign, tmpQuat, tmpQuat);
940
+ }
941
+ const s = d[o + 4];
942
+ Matrix4x4.compose(tmpScale.setXYZ(s, s, s), tmpQuat, tmpPos.setXYZ(x, y, z), tmpMatrix);
943
+ for (const part of parts){
944
+ const mesh = new Mesh(this.scene, part.primitive.get(), part.material.get());
945
+ mesh.sealed = true;
946
+ mesh.castShadow = layer._castShadow;
947
+ mesh.gpuPickable = false;
948
+ mesh.parent = group;
949
+ mesh.setLocalTransform(Matrix4x4.multiply(tmpMatrix, part.matrix, tmpMatrix2));
950
+ // Chunks are built in updatePerCamera, after the frame update that refreshes the
951
+ // matrices meshes draw with; without this the group draws them where they were created
952
+ mesh.syncDrawableTransform();
953
+ }
954
+ for (const t of templates){
955
+ const node = new SceneNode(this.scene);
956
+ node.sealed = true;
957
+ node.parent = colliders;
958
+ node.setLocalTransform(Matrix4x4.multiply(tmpMatrix, t.matrix, tmpMatrix2));
959
+ const collider = new Collider();
960
+ collider.shape = t.shape;
961
+ collider.size = t.size;
962
+ collider.radius = t.radius;
963
+ collider.height = t.height;
964
+ collider.offset = t.offset;
965
+ collider.friction = t.friction;
966
+ collider.restitution = t.restitution;
967
+ collider.layer = t.layer;
968
+ node.physics = new NodePhysics({
969
+ colliders: [
970
+ collider
971
+ ]
972
+ });
973
+ }
974
+ }
975
+ }
976
+ let chunks = this._chunks.get(layer);
977
+ if (!chunks) {
978
+ chunks = new Map();
979
+ this._chunks.set(layer, chunks);
980
+ }
981
+ chunks.set(key, {
982
+ layer,
983
+ key,
984
+ group,
985
+ colliders,
986
+ minX: cx * size,
987
+ minZ: cz * size,
988
+ maxX: (cx + 1) * size,
989
+ maxZ: (cz + 1) * size,
990
+ visible: true
991
+ });
992
+ }
993
+ /**
994
+ * The chunk nodes built for this system, to tell them apart from other scene nodes
995
+ * (e.g. to skip the foliage's own colliders when looking for the ground)
996
+ * @param node - A scene node
997
+ * @returns Whether the node is, or is below, a chunk of this system
998
+ */ ownsNode(node) {
999
+ while(node && node !== this){
1000
+ if (node.parent === this && node.sealed) {
1001
+ return true;
1002
+ }
1003
+ node = node.parent;
1004
+ }
1005
+ return false;
1006
+ }
1007
+ /** {@inheritDoc SceneNode.onDispose} */ onDispose() {
1008
+ this._buildSerial++;
1009
+ this.clearChunks();
1010
+ for (const layer of this._layers){
1011
+ layer._owner = null;
1012
+ layer._dispose();
1013
+ }
1014
+ this._layers = [];
1015
+ super.onDispose();
1016
+ }
1017
+ }
1018
+
1019
+ export { FOLIAGE_INSTANCE_STRIDE, FoliageDensityMask, FoliageLayer, FoliageSystem };
1020
+ //# sourceMappingURL=foliage.js.map