@zephyr3d/scene 0.9.27 → 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 (502) 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 +54 -0
  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 +279 -55
  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 +171 -1
  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 +104 -178
  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 +25436 -15990
  109. package/dist/index.js +65 -11
  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/lambert.js +4 -1
  118. package/dist/material/lambert.js.map +1 -1
  119. package/dist/material/material.js +66 -4
  120. package/dist/material/material.js.map +1 -1
  121. package/dist/material/meshmaterial.js +118 -45
  122. package/dist/material/meshmaterial.js.map +1 -1
  123. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  124. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  125. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  126. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  127. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +34 -61
  128. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  129. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -2
  130. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  131. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +2 -1
  132. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  133. package/dist/material/mixins/lit.js +191 -83
  134. package/dist/material/mixins/lit.js.map +1 -1
  135. package/dist/material/mixins/pbr/common.js +31 -206
  136. package/dist/material/mixins/pbr/common.js.map +1 -1
  137. package/dist/material/mtoon.js +1 -1
  138. package/dist/material/mtoon.js.map +1 -1
  139. package/dist/material/pbrmr.js +3 -0
  140. package/dist/material/pbrmr.js.map +1 -1
  141. package/dist/material/pbrsg.js +3 -0
  142. package/dist/material/pbrsg.js.map +1 -1
  143. package/dist/material/sdf_debug.js +78 -0
  144. package/dist/material/sdf_debug.js.map +1 -0
  145. package/dist/material/shader/helper.js +333 -191
  146. package/dist/material/shader/helper.js.map +1 -1
  147. package/dist/material/shader/terrain_blend.js +204 -43
  148. package/dist/material/shader/terrain_blend.js.map +1 -1
  149. package/dist/material/skin.js +331 -297
  150. package/dist/material/skin.js.map +1 -1
  151. package/dist/material/skinprofile.js +1058 -0
  152. package/dist/material/skinprofile.js.map +1 -0
  153. package/dist/material/sss.js +353 -0
  154. package/dist/material/sss.js.map +1 -0
  155. package/dist/material/sss_kernel.js +265 -0
  156. package/dist/material/sss_kernel.js.map +1 -0
  157. package/dist/material/sssprofile.js +879 -0
  158. package/dist/material/sssprofile.js.map +1 -0
  159. package/dist/material/subsurfaceprofile.js +4 -8
  160. package/dist/material/subsurfaceprofile.js.map +1 -1
  161. package/dist/material/terrain-cm.js +464 -188
  162. package/dist/material/terrain-cm.js.map +1 -1
  163. package/dist/material/unlit.js +3 -0
  164. package/dist/material/unlit.js.map +1 -1
  165. package/dist/material/water.js +1261 -1438
  166. package/dist/material/water.js.map +1 -1
  167. package/dist/node_modules/meshoptimizer/LICENSE +21 -0
  168. package/dist/node_modules/meshoptimizer/meshopt_decoder.js +197 -0
  169. package/dist/node_modules/meshoptimizer/meshopt_decoder.js.map +1 -0
  170. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js +677 -0
  171. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js.map +1 -0
  172. package/dist/physics/character.js +226 -0
  173. package/dist/physics/character.js.map +1 -0
  174. package/dist/physics/collider.js +209 -0
  175. package/dist/physics/collider.js.map +1 -0
  176. package/dist/physics/events.js +79 -0
  177. package/dist/physics/events.js.map +1 -0
  178. package/dist/physics/joint.js +272 -0
  179. package/dist/physics/joint.js.map +1 -0
  180. package/dist/physics/node_physics.js +234 -0
  181. package/dist/physics/node_physics.js.map +1 -0
  182. package/dist/physics/part.js +91 -0
  183. package/dist/physics/part.js.map +1 -0
  184. package/dist/physics/rigid_body.js +379 -0
  185. package/dist/physics/rigid_body.js.map +1 -0
  186. package/dist/physics/vehicle.js +335 -0
  187. package/dist/physics/vehicle.js.map +1 -0
  188. package/dist/physics/world.js +25 -0
  189. package/dist/physics/world.js.map +1 -0
  190. package/dist/posteffect/bloom.js +49 -14
  191. package/dist/posteffect/bloom.js.map +1 -1
  192. package/dist/posteffect/motionblur.js +106 -106
  193. package/dist/posteffect/motionblur.js.map +1 -1
  194. package/dist/posteffect/postsss.js +572 -0
  195. package/dist/posteffect/postsss.js.map +1 -0
  196. package/dist/posteffect/sao.js +2 -6
  197. package/dist/posteffect/sao.js.map +1 -1
  198. package/dist/posteffect/skinsss.js +605 -355
  199. package/dist/posteffect/skinsss.js.map +1 -1
  200. package/dist/posteffect/ssgi.js +91 -162
  201. package/dist/posteffect/ssgi.js.map +1 -1
  202. package/dist/posteffect/ssr.js +3 -11
  203. package/dist/posteffect/ssr.js.map +1 -1
  204. package/dist/posteffect/sss.js +4 -13
  205. package/dist/posteffect/sss.js.map +1 -1
  206. package/dist/posteffect/taa.js +1 -0
  207. package/dist/posteffect/taa.js.map +1 -1
  208. package/dist/render/abuffer_oit.js +3 -2
  209. package/dist/render/abuffer_oit.js.map +1 -1
  210. package/dist/render/clipmap.js +179 -64
  211. package/dist/render/clipmap.js.map +1 -1
  212. package/dist/render/cluster_light.js +958 -224
  213. package/dist/render/cluster_light.js.map +1 -1
  214. package/dist/render/cull_visitor.js +25 -5
  215. package/dist/render/cull_visitor.js.map +1 -1
  216. package/dist/render/debug_views.js +37 -0
  217. package/dist/render/debug_views.js.map +1 -0
  218. package/dist/render/depthpass.js +5 -1
  219. package/dist/render/depthpass.js.map +1 -1
  220. package/dist/render/drawable_mixin.js +53 -6
  221. package/dist/render/drawable_mixin.js.map +1 -1
  222. package/dist/render/dualdepthpeeling_oit.js +5 -5
  223. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  224. package/dist/render/envlight.js +196 -113
  225. package/dist/render/envlight.js.map +1 -1
  226. package/dist/render/fbm_wavegenerator.js +5 -10
  227. package/dist/render/fbm_wavegenerator.js.map +1 -1
  228. package/dist/render/fft_wavegenerator.js +247 -157
  229. package/dist/render/fft_wavegenerator.js.map +1 -1
  230. package/dist/render/gerstner_wavegenerator.js +16 -38
  231. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  232. package/dist/render/gi/probe_volume.js +1334 -0
  233. package/dist/render/gi/probe_volume.js.map +1 -0
  234. package/dist/render/gi/scene_gi.js +282 -0
  235. package/dist/render/gi/scene_gi.js.map +1 -0
  236. package/dist/render/gi/voxel_atlas.js +198 -0
  237. package/dist/render/gi/voxel_atlas.js.map +1 -0
  238. package/dist/render/gi/voxel_lighting.js +652 -0
  239. package/dist/render/gi/voxel_lighting.js.map +1 -0
  240. package/dist/render/gi/voxel_scene.js +642 -0
  241. package/dist/render/gi/voxel_scene.js.map +1 -0
  242. package/dist/render/gi/voxelize_pass.js +223 -0
  243. package/dist/render/gi/voxelize_pass.js.map +1 -0
  244. package/dist/render/globalbindgroup_allocator.js +3 -2
  245. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  246. package/dist/render/gpu_picking.js +9 -36
  247. package/dist/render/gpu_picking.js.map +1 -1
  248. package/dist/render/instance_culling.js +499 -0
  249. package/dist/render/instance_culling.js.map +1 -0
  250. package/dist/render/lightpass.js +19 -8
  251. package/dist/render/lightpass.js.map +1 -1
  252. package/dist/render/lod.js +46 -0
  253. package/dist/render/lod.js.map +1 -0
  254. package/dist/render/primitive.js +301 -9
  255. package/dist/render/primitive.js.map +1 -1
  256. package/dist/render/primitive_readback.js +209 -0
  257. package/dist/render/primitive_readback.js.map +1 -0
  258. package/dist/render/render_queue.js +162 -11
  259. package/dist/render/render_queue.js.map +1 -1
  260. package/dist/render/renderer.js +10 -7
  261. package/dist/render/renderer.js.map +1 -1
  262. package/dist/render/rendergraph/blackboard.js +14 -1
  263. package/dist/render/rendergraph/blackboard.js.map +1 -1
  264. package/dist/render/rendergraph/executor.js +136 -0
  265. package/dist/render/rendergraph/executor.js.map +1 -1
  266. package/dist/render/rendergraph/forward_plus_builder.js +272 -55
  267. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  268. package/dist/render/rendergraph/frame_graph_context.js +41 -0
  269. package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
  270. package/dist/render/rendergraph/scene_render_context.js +31 -2
  271. package/dist/render/rendergraph/scene_render_context.js.map +1 -1
  272. package/dist/render/rendergraph/types.js.map +1 -1
  273. package/dist/render/renderpass.js +28 -5
  274. package/dist/render/renderpass.js.map +1 -1
  275. package/dist/render/sdf/box_allocator.js +98 -0
  276. package/dist/render/sdf/box_allocator.js.map +1 -0
  277. package/dist/render/sdf/global_sdf.js +865 -0
  278. package/dist/render/sdf/global_sdf.js.map +1 -0
  279. package/dist/render/sdf/scene_sdf.js +562 -0
  280. package/dist/render/sdf/scene_sdf.js.map +1 -0
  281. package/dist/render/sdf/sdf_atlas.js +227 -0
  282. package/dist/render/sdf/sdf_atlas.js.map +1 -0
  283. package/dist/render/sdf/sdf_programs.js +42 -0
  284. package/dist/render/sdf/sdf_programs.js.map +1 -0
  285. package/dist/render/sdf/sdf_view.js +199 -0
  286. package/dist/render/sdf/sdf_view.js.map +1 -0
  287. package/dist/render/sdf/waterline.js +610 -0
  288. package/dist/render/sdf/waterline.js.map +1 -0
  289. package/dist/render/shadow_mask_pass.js +142 -25
  290. package/dist/render/shadow_mask_pass.js.map +1 -1
  291. package/dist/render/shore_wave_generator.js +1193 -0
  292. package/dist/render/shore_wave_generator.js.map +1 -0
  293. package/dist/render/sky.js +516 -86
  294. package/dist/render/sky.js.map +1 -1
  295. package/dist/render/transmission_thickness_pass.js +477 -0
  296. package/dist/render/transmission_thickness_pass.js.map +1 -0
  297. package/dist/render/underwater.js +58 -158
  298. package/dist/render/underwater.js.map +1 -1
  299. package/dist/render/virtualtexture/virtual_texture.js +1214 -0
  300. package/dist/render/virtualtexture/virtual_texture.js.map +1 -0
  301. package/dist/render/volumetric_cloud/cloud_common.js +472 -0
  302. package/dist/render/volumetric_cloud/cloud_common.js.map +1 -0
  303. package/dist/render/volumetric_cloud/cloud_noise.js +189 -0
  304. package/dist/render/volumetric_cloud/cloud_noise.js.map +1 -0
  305. package/dist/render/volumetric_cloud/debug_view.js +131 -0
  306. package/dist/render/volumetric_cloud/debug_view.js.map +1 -0
  307. package/dist/render/volumetric_cloud/resources.js +380 -0
  308. package/dist/render/volumetric_cloud/resources.js.map +1 -0
  309. package/dist/render/volumetric_cloud/sky_cache.js +380 -0
  310. package/dist/render/volumetric_cloud/sky_cache.js.map +1 -0
  311. package/dist/render/volumetric_cloud/volumetric_cloud.js +318 -0
  312. package/dist/render/volumetric_cloud/volumetric_cloud.js.map +1 -0
  313. package/dist/render/water_caustics.js +134 -319
  314. package/dist/render/water_caustics.js.map +1 -1
  315. package/dist/render/water_foam.js +627 -0
  316. package/dist/render/water_foam.js.map +1 -0
  317. package/dist/render/water_interaction.js +1795 -0
  318. package/dist/render/water_interaction.js.map +1 -0
  319. package/dist/render/weightedblended_oit.js +3 -3
  320. package/dist/render/weightedblended_oit.js.map +1 -1
  321. package/dist/scene/basesprite.js +9 -4
  322. package/dist/scene/basesprite.js.map +1 -1
  323. package/dist/scene/batchgroup.js +108 -12
  324. package/dist/scene/batchgroup.js.map +1 -1
  325. package/dist/scene/environment.js +28 -7
  326. package/dist/scene/environment.js.map +1 -1
  327. package/dist/scene/foliage.js +1020 -0
  328. package/dist/scene/foliage.js.map +1 -0
  329. package/dist/scene/foliage_buckets.js +147 -0
  330. package/dist/scene/foliage_buckets.js.map +1 -0
  331. package/dist/scene/foliage_mask.js +358 -0
  332. package/dist/scene/foliage_mask.js.map +1 -0
  333. package/dist/scene/hair.js +15 -4
  334. package/dist/scene/hair.js.map +1 -1
  335. package/dist/scene/light.js +179 -13
  336. package/dist/scene/light.js.map +1 -1
  337. package/dist/scene/mesh.js +327 -45
  338. package/dist/scene/mesh.js.map +1 -1
  339. package/dist/scene/meshdrawable.js +6 -0
  340. package/dist/scene/meshdrawable.js.map +1 -1
  341. package/dist/scene/msdftext.js +9 -3
  342. package/dist/scene/msdftext.js.map +1 -1
  343. package/dist/scene/msdftextsprite.js +9 -3
  344. package/dist/scene/msdftextsprite.js.map +1 -1
  345. package/dist/scene/particlesys.js +8 -2
  346. package/dist/scene/particlesys.js.map +1 -1
  347. package/dist/scene/physics_settings.js +157 -0
  348. package/dist/scene/physics_settings.js.map +1 -0
  349. package/dist/scene/scene.js +190 -44
  350. package/dist/scene/scene.js.map +1 -1
  351. package/dist/scene/scene_node.js +147 -6
  352. package/dist/scene/scene_node.js.map +1 -1
  353. package/dist/scene/terrain-cm/bladegrassmaterial.js +735 -0
  354. package/dist/scene/terrain-cm/bladegrassmaterial.js.map +1 -0
  355. package/dist/scene/terrain-cm/grass.js +881 -42
  356. package/dist/scene/terrain-cm/grass.js.map +1 -1
  357. package/dist/scene/terrain-cm/grass_gpu.js +929 -0
  358. package/dist/scene/terrain-cm/grass_gpu.js.map +1 -0
  359. package/dist/scene/terrain-cm/grassmaterial.js +180 -9
  360. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  361. package/dist/scene/terrain-cm/terrain-cm.js +465 -36
  362. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  363. package/dist/scene/terrain-cm/terrain_gi_albedo.js +257 -0
  364. package/dist/scene/terrain-cm/terrain_gi_albedo.js.map +1 -0
  365. package/dist/scene/terrain-cm/terrain_rvt.js +395 -0
  366. package/dist/scene/terrain-cm/terrain_rvt.js.map +1 -0
  367. package/dist/scene/update_queue.js +54 -0
  368. package/dist/scene/update_queue.js.map +1 -0
  369. package/dist/scene/water.js +633 -268
  370. package/dist/scene/water.js.map +1 -1
  371. package/dist/scene/water_surface_sampler.js +324 -0
  372. package/dist/scene/water_surface_sampler.js.map +1 -0
  373. package/dist/scene/wind.js +317 -0
  374. package/dist/scene/wind.js.map +1 -0
  375. package/dist/shaders/atmosphere.js +388 -166
  376. package/dist/shaders/atmosphere.js.map +1 -1
  377. package/dist/shaders/fog.js +100 -32
  378. package/dist/shaders/fog.js.map +1 -1
  379. package/dist/shaders/gi.js +365 -0
  380. package/dist/shaders/gi.js.map +1 -0
  381. package/dist/shaders/ltc_rect.js +202 -0
  382. package/dist/shaders/ltc_rect.js.map +1 -0
  383. package/dist/shaders/misc.js +1 -10
  384. package/dist/shaders/misc.js.map +1 -1
  385. package/dist/shaders/noise.js +5 -1
  386. package/dist/shaders/noise.js.map +1 -1
  387. package/dist/shaders/probes.js +309 -0
  388. package/dist/shaders/probes.js.map +1 -0
  389. package/dist/shaders/sdf.js +537 -0
  390. package/dist/shaders/sdf.js.map +1 -0
  391. package/dist/shaders/shadow.js +104 -70
  392. package/dist/shaders/shadow.js.map +1 -1
  393. package/dist/shaders/skin_brdf.js +243 -0
  394. package/dist/shaders/skin_brdf.js.map +1 -0
  395. package/dist/shaders/ssgi.js +63 -0
  396. package/dist/shaders/ssgi.js.map +1 -0
  397. package/dist/shaders/ssgi_reprojection.js +118 -0
  398. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  399. package/dist/shaders/ssr.js +6 -159
  400. package/dist/shaders/ssr.js.map +1 -1
  401. package/dist/shaders/temporal.js +38 -27
  402. package/dist/shaders/temporal.js.map +1 -1
  403. package/dist/shaders/water.js +32 -82
  404. package/dist/shaders/water.js.map +1 -1
  405. package/dist/shaders/water_medium.js +7 -21
  406. package/dist/shaders/water_medium.js.map +1 -1
  407. package/dist/shadow/dom.js +110 -19
  408. package/dist/shadow/dom.js.map +1 -1
  409. package/dist/shadow/esm.js +3 -3
  410. package/dist/shadow/esm.js.map +1 -1
  411. package/dist/shadow/pcf_opt.js +15 -48
  412. package/dist/shadow/pcf_opt.js.map +1 -1
  413. package/dist/shadow/pcf_pd.js +15 -53
  414. package/dist/shadow/pcf_pd.js.map +1 -1
  415. package/dist/shadow/pcss.js +34 -9
  416. package/dist/shadow/pcss.js.map +1 -1
  417. package/dist/shadow/shadow_impl.js +3 -8
  418. package/dist/shadow/shadow_impl.js.map +1 -1
  419. package/dist/shadow/shadow_region.js +40 -2
  420. package/dist/shadow/shadow_region.js.map +1 -1
  421. package/dist/shadow/shadowmapper.js +93 -53
  422. package/dist/shadow/shadowmapper.js.map +1 -1
  423. package/dist/shadow/ssm.js +18 -72
  424. package/dist/shadow/ssm.js.map +1 -1
  425. package/dist/shadow/vsm.js +3 -3
  426. package/dist/shadow/vsm.js.map +1 -1
  427. package/dist/shapes/shape.js +44 -1
  428. package/dist/shapes/shape.js.map +1 -1
  429. package/dist/utility/buoyancy.js +287 -0
  430. package/dist/utility/buoyancy.js.map +1 -0
  431. package/dist/utility/physical.js +10 -1
  432. package/dist/utility/physical.js.map +1 -1
  433. package/dist/utility/pmrem.js +17 -43
  434. package/dist/utility/pmrem.js.map +1 -1
  435. package/dist/utility/sdf/bake.js +435 -0
  436. package/dist/utility/sdf/bake.js.map +1 -0
  437. package/dist/utility/sdf/bvh.js +576 -0
  438. package/dist/utility/sdf/bvh.js.map +1 -0
  439. package/dist/utility/serialization/manager.js +34 -6
  440. package/dist/utility/serialization/manager.js.map +1 -1
  441. package/dist/utility/serialization/scene/animation.js +46 -5
  442. package/dist/utility/serialization/scene/animation.js.map +1 -1
  443. package/dist/utility/serialization/scene/batch.js +11 -4
  444. package/dist/utility/serialization/scene/batch.js.map +1 -1
  445. package/dist/utility/serialization/scene/camera.js +87 -254
  446. package/dist/utility/serialization/scene/camera.js.map +1 -1
  447. package/dist/utility/serialization/scene/cloth.js +25 -0
  448. package/dist/utility/serialization/scene/cloth.js.map +1 -0
  449. package/dist/utility/serialization/scene/common.js +14 -6
  450. package/dist/utility/serialization/scene/common.js.map +1 -1
  451. package/dist/utility/serialization/scene/foliage.js +821 -0
  452. package/dist/utility/serialization/scene/foliage.js.map +1 -0
  453. package/dist/utility/serialization/scene/hair.js +11 -4
  454. package/dist/utility/serialization/scene/hair.js.map +1 -1
  455. package/dist/utility/serialization/scene/light.js +115 -7
  456. package/dist/utility/serialization/scene/light.js.map +1 -1
  457. package/dist/utility/serialization/scene/material.js +388 -220
  458. package/dist/utility/serialization/scene/material.js.map +1 -1
  459. package/dist/utility/serialization/scene/mesh.js +69 -4
  460. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  461. package/dist/utility/serialization/scene/node.js +140 -5
  462. package/dist/utility/serialization/scene/node.js.map +1 -1
  463. package/dist/utility/serialization/scene/node_physics.js +1318 -0
  464. package/dist/utility/serialization/scene/node_physics.js.map +1 -0
  465. package/dist/utility/serialization/scene/particle.js +11 -4
  466. package/dist/utility/serialization/scene/particle.js.map +1 -1
  467. package/dist/utility/serialization/scene/physics.js +120 -0
  468. package/dist/utility/serialization/scene/physics.js.map +1 -0
  469. package/dist/utility/serialization/scene/primitive.js +124 -10
  470. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  471. package/dist/utility/serialization/scene/scene.js +1687 -51
  472. package/dist/utility/serialization/scene/scene.js.map +1 -1
  473. package/dist/utility/serialization/scene/sprite.js +11 -4
  474. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  475. package/dist/utility/serialization/scene/terrain.js +163 -33
  476. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  477. package/dist/utility/serialization/scene/text.js +11 -4
  478. package/dist/utility/serialization/scene/text.js.map +1 -1
  479. package/dist/utility/serialization/scene/water.js +1543 -264
  480. package/dist/utility/serialization/scene/water.js.map +1 -1
  481. package/dist/utility/serialization/types.js.map +1 -1
  482. package/dist/utility/shprojector.js +10 -22
  483. package/dist/utility/shprojector.js.map +1 -1
  484. package/dist/utility/textures/foam.js +170 -0
  485. package/dist/utility/textures/foam.js.map +1 -0
  486. package/dist/utility/textures/ggxlut.js +17 -43
  487. package/dist/utility/textures/ggxlut.js.map +1 -1
  488. package/dist/utility/textures/ltcdata.js +4 -4
  489. package/dist/utility/textures/ltcdata.js.map +1 -1
  490. package/dist/utility/textures/ltclut.js +16 -6
  491. package/dist/utility/textures/ltclut.js.map +1 -1
  492. package/dist/utility/unsupported.js +24 -0
  493. package/dist/utility/unsupported.js.map +1 -0
  494. package/dist/values.js +13 -1
  495. package/dist/values.js.map +1 -1
  496. package/package.json +25 -12
  497. package/src/asset/loaders/ktx2/basis/LICENSE +201 -0
  498. package/src/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  499. package/src/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  500. package/src/asset/meshoptimizer/LICENSE +21 -0
  501. package/dist/animation/joint_dynamics/convex_collider.js +0 -320
  502. package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
@@ -6,33 +6,34 @@ import '../shaders/atmosphere.js';
6
6
  import { fetchSampler } from '../utility/misc.js';
7
7
  import { getDevice } from '../app/api.js';
8
8
 
9
+ /**
10
+ * Size of the largest cascade over the peak wavelength of the spectrum,
11
+ * 2 pi sqrt(2) U^2 / g for the Phillips spectrum at wind speed U: the peak
12
+ * repeats some 14 times across it, and the band below it, where no wave
13
+ * height is left, stays out of every cascade.
14
+ */ const CASCADE_PEAK_SPAN = 14;
15
+ /**
16
+ * Size of a cascade over that of the next smaller one. Each covers the
17
+ * wavelengths between the next larger one's Nyquist and its own, about three
18
+ * octaves at this ratio; not an integer, so the tiles of the cascades do not
19
+ * repeat in step.
20
+ */ const CASCADE_RATIO = 7.5;
21
+ /** Sizes of the largest cascade are kept within, in meters. */ const CASCADE_MIN_SIZE = 16;
22
+ const CASCADE_MAX_SIZE = 16384;
9
23
  function getDefaultBuildParams() {
10
24
  return {
11
25
  cascades: [
12
26
  {
13
- size: 400.0,
14
27
  strength: 0.4,
15
- croppiness: -1.5,
16
- minWave: 0,
17
- // The whole patch. Capping this at 100 discarded every wavelength
18
- // between 100 and 400 m, which is exactly where the Phillips peak
19
- // moves once |wind| passes ~10 m/s - the wind then had nothing left
20
- // to put energy into and the swell stopped growing.
21
- maxWave: 400
28
+ croppiness: -1.5
22
29
  },
23
30
  {
24
- size: 100.0,
25
31
  strength: 0.4,
26
- croppiness: -1.2,
27
- minWave: 0,
28
- maxWave: 100
32
+ croppiness: -1.2
29
33
  },
30
34
  {
31
- size: 15,
32
- strength: 0.2,
33
- croppiness: -0.5,
34
- minWave: 0,
35
- maxWave: 7
35
+ strength: 0.4,
36
+ croppiness: -0.5
36
37
  }
37
38
  ],
38
39
  resolution: 256,
@@ -46,6 +47,22 @@ const RENDER_NONE = 0;
46
47
  const RENDER_NORMAL = 1;
47
48
  const RENDER_TWO_PASS = 2;
48
49
  const THREAD_GROUP_SIZE = 16;
50
+ /**
51
+ * Mip levels of a cascade over which the share of its slope variance kept is
52
+ * tabulated (levels 1 to this); level 0 keeps it all, the level past the table
53
+ * none.
54
+ */ const SLOPE_LOD_LEVELS = 8;
55
+ /**
56
+ * Anisotropy of the slope sampling. At 1 the mip level follows the pixel's
57
+ * long axis: soft at grazing views, but the finest near the camera. Higher
58
+ * picks it from the short axis, and the few taps the hardware takes along the
59
+ * long one leave the shortest waves to alias into speckle close by.
60
+ */ const SLOPE_MAX_ANISOTROPY = 1;
61
+ /**
62
+ * Scale of the screen derivatives the slopes are filtered by, log2 of it a bias
63
+ * of the mip level. Above 1 hides the speckle of a higher anisotropy, but
64
+ * softens the near waves by as much.
65
+ */ const SLOPE_FILTER_SCALE = 1;
49
66
  /**
50
67
  * This class generates a 2D ocean field using the Fast Fourier Transform (FFT) algorithm.
51
68
  * @public
@@ -76,6 +93,8 @@ const THREAD_GROUP_SIZE = 16;
76
93
  _instanceData;
77
94
  _ifftTextures;
78
95
  _cascades;
96
+ /** Per cascade: slope (var x, var z, cov xz) in world units, and its texel size */ _slopeVariances;
97
+ /** Per cascade, two each: share of its slope variance mip levels 1-4 and 5-8 keep */ _slopeRetained;
79
98
  _paramsChanged;
80
99
  _version;
81
100
  _resolutionChanged;
@@ -90,7 +109,7 @@ const THREAD_GROUP_SIZE = 16;
90
109
  super();
91
110
  const device = getDevice();
92
111
  const renderTargetFloat16 = device.getDeviceCaps().textureCaps.supportHalfFloatColorBuffer;
93
- const maxDrawBuffers = /*device.type !== 'webgl' && */ renderTargetFloat16 ? device.getDeviceCaps().framebufferCaps.maxDrawBuffers : 0;
112
+ const maxDrawBuffers = renderTargetFloat16 ? device.getDeviceCaps().framebufferCaps.maxDrawBuffers : 0;
94
113
  this._textureFormat = 'rgba16f';
95
114
  this._h0TextureFormat = 'rgba16f';
96
115
  this._dataTextureFormat = 'rgba16f';
@@ -177,6 +196,12 @@ const THREAD_GROUP_SIZE = 16;
177
196
  new Vector4(),
178
197
  new Vector4()
179
198
  ];
199
+ this._slopeVariances = [
200
+ new Vector4(),
201
+ new Vector4(),
202
+ new Vector4()
203
+ ];
204
+ this._slopeRetained = new Float32Array(6 * 4);
180
205
  this._updateRenderStates = getDevice().createRenderStateSet();
181
206
  this._updateRenderStates.useRasterizerState().setCullMode('none');
182
207
  this._updateRenderStates.useDepthState().enableTest(false).enableWrite(false);
@@ -190,17 +215,7 @@ const THREAD_GROUP_SIZE = 16;
190
215
  clone() {
191
216
  return new FFTWaveGenerator(this._params);
192
217
  }
193
- /*
194
- get params() {
195
- return this._params;
196
- }
197
- set params(val: OceanFieldBuildParams) {
198
- if (val && val !== this._params) {
199
- this._params = val;
200
- this.paramsChanged();
201
- }
202
- }
203
- */ paramsChanged() {
218
+ paramsChanged() {
204
219
  this._paramsChanged = true;
205
220
  this._version++;
206
221
  }
@@ -241,18 +256,18 @@ const THREAD_GROUP_SIZE = 16;
241
256
  this.paramsChanged();
242
257
  }
243
258
  }
244
- /** Gets the wave length for the specified cascade */ getWaveLength(cascade) {
245
- return this._params.cascades[cascade].size;
246
- }
247
259
  /**
248
- * Sets the wave length for the specified cascade
260
+ * Gets the size of the patch the specified cascade simulates, in meters.
261
+ *
262
+ * The sizes follow the wind: the largest cascade spans the peak wavelength of
263
+ * the spectrum some times over, and each next one is a fixed fraction of it,
264
+ * so the three cover the waves that carry height and slope at any wind speed.
249
265
  * @param cascade - The cascade index
250
- * @param length - The new wave length for the specified cascade
251
- */ setWaveLength(cascade, length) {
252
- if (this._params.cascades[cascade].size !== length) {
253
- this._params.cascades[cascade].size = length;
254
- this.paramsChanged();
255
- }
266
+ */ getWaveLength(cascade) {
267
+ const windSpeed = Math.hypot(this._params.wind.x, this._params.wind.y);
268
+ const peak = 2 * Math.PI * Math.SQRT2 * windSpeed * windSpeed / 9.81;
269
+ const largest = Math.min(Math.max(peak * CASCADE_PEAK_SPAN, CASCADE_MIN_SIZE), CASCADE_MAX_SIZE);
270
+ return largest / Math.pow(CASCADE_RATIO, cascade);
256
271
  }
257
272
  /** Gets the wave strength for the specified cascade */ getWaveStrength(cascade) {
258
273
  return this._params.cascades[cascade].strength;
@@ -344,12 +359,19 @@ const THREAD_GROUP_SIZE = 16;
344
359
  this._h0BindGroup.setValue('resolution', this._params.resolution);
345
360
  this._h0BindGroup.setValue('wind', this._params.wind);
346
361
  this._h0BindGroup.setValue('alignment', this._params.alignment);
347
- for(let i = 0; i < this._params.cascades.length; i++){
348
- this._cascades[i].x = this._params.cascades[i].size;
349
- this._cascades[i].y = this._params.cascades[i].strength * 0.081 / (this._params.cascades[i].size * this._params.cascades[i].size);
350
- this._cascades[i].z = 2 * Math.PI / this._params.cascades[i].maxWave;
351
- this._cascades[i].w = 2 * Math.PI / this._params.cascades[i].minWave;
362
+ // Bands split as in Bruneton's ocean demo (and Ceto, its Unity port): each
363
+ // cascade keeps the wave numbers outside the square |kx|, |ky| < kMin, kMin the
364
+ // Nyquist pi N / L of the next larger cascade (pi / L for the largest), and
365
+ // stops at its own Nyquist, so the cascades share no wave number.
366
+ const cascades = this._params.cascades;
367
+ for(let i = 0; i < cascades.length; i++){
368
+ const size = this.getWaveLength(i);
369
+ this._cascades[i].x = size;
370
+ this._cascades[i].y = cascades[i].strength * 0.081 / (size * size);
371
+ this._cascades[i].z = i === 0 ? Math.PI / size : Math.PI * this._params.resolution / this.getWaveLength(i - 1);
372
+ this._cascades[i].w = 0;
352
373
  }
374
+ this.computeSlopeVariances();
353
375
  this._h0BindGroup.setValue('cascade0', this._cascades[0]);
354
376
  this._h0BindGroup.setValue('cascade1', this._cascades[1]);
355
377
  this._h0BindGroup.setValue('cascade2', this._cascades[2]);
@@ -362,38 +384,90 @@ const THREAD_GROUP_SIZE = 16;
362
384
  FFTWaveGenerator._globals.quad.draw();
363
385
  }
364
386
  }
387
+ /**
388
+ * Expected slope covariance of each cascade, summed over the same spectrum the
389
+ * h0 and hk programs build: E|h(k)|^2 = 2 P(k) (a(k) + a(-k)), P the Phillips
390
+ * spectrum halved as h0 takes it, a the wind alignment, and the slopes i k h(k)
391
+ * with the Nyquist row and column zeroed. The inverse FFT is unnormalized, so
392
+ * a field's variance is the plain sum over the grid.
393
+ *
394
+ * Also how much of it each mip level of the cascade keeps: a level halving the
395
+ * texels keeps the wave numbers below its Nyquist along both axes.
396
+ * @internal
397
+ */ computeSlopeVariances() {
398
+ const N = this._params.resolution;
399
+ const wind = this._params.wind;
400
+ const windLen = Math.hypot(wind.x, wind.y);
401
+ const wx = windLen > 0 ? wind.x / windLen : 1;
402
+ const wz = windLen > 0 ? wind.y / windLen : 0;
403
+ const L = windLen * windLen / 9.81;
404
+ const L2 = L * L;
405
+ const alignment = this._params.alignment;
406
+ for(let i = 0; i < 3; i++){
407
+ const size = this._cascades[i].x;
408
+ const A = this._cascades[i].y;
409
+ const minK = this._cascades[i].z;
410
+ let xx = 0;
411
+ let zz = 0;
412
+ let xz = 0;
413
+ // Variance whose wave numbers are cut first at level 1 + n
414
+ const cut = new Array(SLOPE_LOD_LEVELS + 1).fill(0);
415
+ const nyquist = Math.PI * N / size;
416
+ if (size > 1e-3 && L2 > 0) {
417
+ const dk = Math.PI * 2 / size;
418
+ for(let cy = 1; cy < N; cy++){
419
+ const kz = (cy - N / 2) * dk;
420
+ for(let cx = 1; cx < N; cx++){
421
+ const kx = (cx - N / 2) * dk;
422
+ if (Math.abs(kx) < minK && Math.abs(kz) < minK) {
423
+ continue;
424
+ }
425
+ const k2 = kx * kx + kz * kz;
426
+ let e = A / (k2 * k2) * Math.exp(-1 / (k2 * L2));
427
+ if (alignment > 0) {
428
+ const c = (kx * wx + kz * wz) / Math.sqrt(k2);
429
+ e *= Math.pow(Math.max(0, c), alignment) + Math.pow(Math.max(0, -c), alignment);
430
+ } else {
431
+ e *= 2;
432
+ }
433
+ xx += kx * kx * e;
434
+ zz += kz * kz * e;
435
+ xz += kx * kz * e;
436
+ // Kept up to the level whose Nyquist nyquist / 2^level it still lies below
437
+ const kept = Math.log2(nyquist / Math.max(Math.abs(kx), Math.abs(kz)));
438
+ cut[Math.min(Math.max(Math.ceil(kept), 1), SLOPE_LOD_LEVELS + 1) - 1] += k2 * e;
439
+ }
440
+ }
441
+ }
442
+ this._slopeVariances[i].setXYZW(xx, zz, xz, size / N);
443
+ const total = xx + zz;
444
+ let kept = total;
445
+ for(let level = 1; level <= SLOPE_LOD_LEVELS; level++){
446
+ kept -= cut[level - 1];
447
+ this._slopeRetained[i * SLOPE_LOD_LEVELS + level - 1] = total > 0 ? Math.max(kept / total, 0) : 0;
448
+ }
449
+ }
450
+ }
365
451
  /** @internal */ getNoiseTexture(size, randomSeed) {
366
452
  const device = getDevice();
367
- // Keyed on the seed as well as the size. Keying on size alone let the first
368
- // generator of a given resolution decide the noise for every later one,
369
- // silently discarding their seeds - two differently seeded oceans came out
370
- // identical, and which seed won depended on creation order.
453
+ // Keyed on the seed as well as the size: both select the noise.
371
454
  const key = `${size}:${randomSeed}`;
372
455
  let tex = FFTWaveGenerator._globals.noiseTextures.get(key);
373
456
  if (!tex) {
374
- tex = device.createTexture2D(device.type === 'webgl' ? 'rgba32f' : 'rg32f', size, size, {
457
+ tex = device.createTexture2D('rg32f', size, size, {
375
458
  mipmapping: false
376
459
  });
377
460
  tex.name = `noiseTex${size}_${randomSeed}`;
378
- tex.update(this.getNoise2d(size, randomSeed, device.type === 'webgl'), 0, 0, size, size);
461
+ tex.update(this.getNoise2d(size, randomSeed), 0, 0, size, size);
379
462
  FFTWaveGenerator._globals.noiseTextures.set(key, tex);
380
463
  }
381
464
  return tex;
382
465
  }
383
- /** @internal */ getNoise2d(size, randomSeed, rgba) {
466
+ /** @internal */ getNoise2d(size, randomSeed) {
384
467
  const rand = new PRNG(randomSeed);
385
- if (rgba) {
386
- const array = new Float32Array(size * size * 4);
387
- for(let i = 0; i < size * size; i++){
388
- array[i * 4 + 0] = rand.get();
389
- array[i * 4 + 1] = rand.get();
390
- }
391
- return array;
392
- } else {
393
- return Float32Array.from([
394
- ...Array(size * size * 2)
395
- ].map(()=>rand.get()));
396
- }
468
+ return Float32Array.from([
469
+ ...Array(size * size * 2)
470
+ ].map(()=>rand.get()));
397
471
  }
398
472
  /** @internal */ reverseBits(v, width) {
399
473
  return parseInt(v.toString(2).padStart(width, '0').split('').reverse().join(''), 2);
@@ -439,7 +513,7 @@ const THREAD_GROUP_SIZE = 16;
439
513
  if (!this._instanceData) {
440
514
  const device = getDevice();
441
515
  const h0Textures = this.createNTextures(device, this._h0TextureFormat, this._params.resolution, 3, 'Water-h0', false);
442
- const dataTextures = this.createNTextures(device, this._dataTextureFormat, this._params.resolution, 6, 'Water-data', true);
516
+ const dataTextures = this.createNTextures(device, this._dataTextureFormat, this._params.resolution, 6, 'Water-data', true, true);
443
517
  const spectrumTextures = this.createNTextures(device, this._textureFormat, this._params.resolution, 6, 'Water-spectrum', true);
444
518
  const pingpongTextures = this.createNTextures(device, this._textureFormat, this._params.resolution, 6, 'Water-pingpong', false);
445
519
  this._instanceData = {
@@ -461,17 +535,17 @@ const THREAD_GROUP_SIZE = 16;
461
535
  }
462
536
  return this._instanceData;
463
537
  }
464
- /** @internal */ createNTextures(device, format, size, num, name, linear) {
538
+ /** @internal */ createNTextures(device, format, size, num, name, linear, mipmapping = false) {
465
539
  const options = {
466
540
  samplerOptions: {
467
541
  minFilter: linear ? 'linear' : 'nearest',
468
542
  magFilter: linear ? 'linear' : 'nearest',
469
- mipFilter: 'none',
543
+ mipFilter: mipmapping ? 'linear' : 'none',
470
544
  addressU: 'repeat',
471
545
  addressV: 'repeat'
472
546
  },
473
547
  writable: !!this._useComputeShader,
474
- mipmapping: false
548
+ mipmapping
475
549
  };
476
550
  if (this._useComputeShader) {
477
551
  const tex = device.createTexture2DArray(format, size, size, num, options);
@@ -500,7 +574,7 @@ const THREAD_GROUP_SIZE = 16;
500
574
  this._resolutionChanged = false;
501
575
  this._paramsChanged = false;
502
576
  for(let i = 0; i < 3; i++){
503
- this._sizes[i] = this._params.cascades[i].size;
577
+ this._sizes[i] = this._cascades[i].x;
504
578
  this._croppinesses[i] = this._params.cascades[i].croppiness;
505
579
  }
506
580
  if (this._renderMode === RENDER_NORMAL) {
@@ -512,6 +586,13 @@ const THREAD_GROUP_SIZE = 16;
512
586
  this.ifft2TwoPass();
513
587
  this.postIfft2TwoPass();
514
588
  }
589
+ // The fragment normal reads the slopes filtered to the pixel
590
+ const dataTextures = this.getInstanceData().dataTextures;
591
+ if (Array.isArray(dataTextures)) {
592
+ dataTextures.forEach((tex)=>tex.generateMipmaps());
593
+ } else {
594
+ dataTextures.generateMipmaps();
595
+ }
515
596
  device.popDeviceStates();
516
597
  }
517
598
  /** {@inheritDoc WaveGenerator.needUpdate} */ needUpdate() {
@@ -561,9 +642,6 @@ const THREAD_GROUP_SIZE = 16;
561
642
  this._hkBindGroup.setTexture('h0Texture0', h0Textures[0], nearestRepeatSampler);
562
643
  this._hkBindGroup.setTexture('h0Texture1', h0Textures[1], nearestRepeatSampler);
563
644
  this._hkBindGroup.setTexture('h0Texture2', h0Textures[2], nearestRepeatSampler);
564
- if (device.type === 'webgl') {
565
- this._hkBindGroup.setValue('h0TexSize', new Vector2(h0Textures[0].width, h0Textures[0].height));
566
- }
567
645
  device.setFramebuffer(instanceData.spectrumFramebuffer);
568
646
  FFTWaveGenerator._globals.quad.draw();
569
647
  }
@@ -580,9 +658,6 @@ const THREAD_GROUP_SIZE = 16;
580
658
  this._hkBindGroup4.setTexture('h0Texture0', h0Textures[0], nearestRepeatSampler);
581
659
  this._hkBindGroup4.setTexture('h0Texture1', h0Textures[1], nearestRepeatSampler);
582
660
  this._hkBindGroup4.setValue('t', time);
583
- if (device.type === 'webgl') {
584
- this._hkBindGroup4.setValue('h0TexSize', new Vector2(h0Textures[0].width, h0Textures[0].height));
585
- }
586
661
  device.setFramebuffer(instanceData.spectrumFramebuffer4);
587
662
  FFTWaveGenerator._globals.quad.draw();
588
663
  device.setProgram(FFTWaveGenerator._globals.programs.hkProgram2);
@@ -591,9 +666,6 @@ const THREAD_GROUP_SIZE = 16;
591
666
  this._hkBindGroup2.setValue('sizes', this._sizes);
592
667
  this._hkBindGroup2.setTexture('h0Texture2', h0Textures[2], nearestRepeatSampler);
593
668
  this._hkBindGroup2.setValue('t', time);
594
- if (device.type === 'webgl') {
595
- this._hkBindGroup2.setValue('h0TexSize', new Vector2(h0Textures[0].width, h0Textures[0].height));
596
- }
597
669
  device.setFramebuffer(instanceData.spectrumFramebuffer2);
598
670
  FFTWaveGenerator._globals.quad.draw();
599
671
  }
@@ -634,9 +706,6 @@ const THREAD_GROUP_SIZE = 16;
634
706
  this._fft2hBindGroup.setTexture('spectrum3', pingPongTexture[3], nearestRepeatSampler);
635
707
  this._fft2hBindGroup.setTexture('spectrum4', pingPongTexture[4], nearestRepeatSampler);
636
708
  this._fft2hBindGroup.setTexture('spectrum5', pingPongTexture[5], nearestRepeatSampler);
637
- if (device.type === 'webgl') {
638
- this._fft2hBindGroup.setValue('texSize', new Vector4(pingPongTexture[0].width, pingPongTexture[0].height, butterflyTex.width, butterflyTex.height));
639
- }
640
709
  FFTWaveGenerator._globals.quad.draw();
641
710
  }
642
711
  pingPong = 1 - pingPong; //(pingPong + 1) % 2;
@@ -660,9 +729,6 @@ const THREAD_GROUP_SIZE = 16;
660
729
  this._fft2vBindGroup.setTexture('spectrum3', pingPongTexture[3], nearestRepeatSampler);
661
730
  this._fft2vBindGroup.setTexture('spectrum4', pingPongTexture[4], nearestRepeatSampler);
662
731
  this._fft2vBindGroup.setTexture('spectrum5', pingPongTexture[5], nearestRepeatSampler);
663
- if (device.type === 'webgl') {
664
- this._fft2vBindGroup.setValue('texSize', new Vector4(pingPongTexture[0].width, pingPongTexture[0].height, butterflyTex.width, butterflyTex.height));
665
- }
666
732
  FFTWaveGenerator._globals.quad.draw();
667
733
  }
668
734
  pingPong = 1 - pingPong;
@@ -732,9 +798,6 @@ const THREAD_GROUP_SIZE = 16;
732
798
  fft2hBindGroup4.setTexture('spectrum1', pingPongTextures[pingPong][1], nearestRepeatSampler);
733
799
  fft2hBindGroup4.setTexture('spectrum2', pingPongTextures[pingPong][2], nearestRepeatSampler);
734
800
  fft2hBindGroup4.setTexture('spectrum3', pingPongTextures[pingPong][3], nearestRepeatSampler);
735
- if (device.type === 'webgl') {
736
- fft2hBindGroup4.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
737
- }
738
801
  FFTWaveGenerator._globals.quad.draw();
739
802
  device.setFramebuffer(pingPongFramebuffers2[pingPong]);
740
803
  device.setProgram(FFTWaveGenerator._globals.programs.fft2hProgram2);
@@ -744,9 +807,6 @@ const THREAD_GROUP_SIZE = 16;
744
807
  fft2hBindGroup2.setValue('phase', phase);
745
808
  fft2hBindGroup2.setTexture('spectrum4', pingPongTextures[pingPong][4], nearestRepeatSampler);
746
809
  fft2hBindGroup2.setTexture('spectrum5', pingPongTextures[pingPong][5], nearestRepeatSampler);
747
- if (device.type === 'webgl') {
748
- fft2hBindGroup2.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
749
- }
750
810
  FFTWaveGenerator._globals.quad.draw();
751
811
  pingPong = (pingPong + 1) % 2;
752
812
  }
@@ -762,9 +822,6 @@ const THREAD_GROUP_SIZE = 16;
762
822
  fft2vBindGroup4.setTexture('spectrum1', pingPongTextures[pingPong][1], nearestRepeatSampler);
763
823
  fft2vBindGroup4.setTexture('spectrum2', pingPongTextures[pingPong][2], nearestRepeatSampler);
764
824
  fft2vBindGroup4.setTexture('spectrum3', pingPongTextures[pingPong][3], nearestRepeatSampler);
765
- if (device.type === 'webgl') {
766
- fft2vBindGroup4.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
767
- }
768
825
  FFTWaveGenerator._globals.quad.draw();
769
826
  device.setFramebuffer(pingPongFramebuffers2[pingPong]);
770
827
  device.setProgram(FFTWaveGenerator._globals.programs.fft2vProgram2);
@@ -774,9 +831,6 @@ const THREAD_GROUP_SIZE = 16;
774
831
  fft2vBindGroup2.setValue('phase', phase);
775
832
  fft2vBindGroup2.setTexture('spectrum4', pingPongTextures[pingPong][4], nearestRepeatSampler);
776
833
  fft2vBindGroup2.setTexture('spectrum5', pingPongTextures[pingPong][5], nearestRepeatSampler);
777
- if (device.type === 'webgl') {
778
- fft2vBindGroup2.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
779
- }
780
834
  FFTWaveGenerator._globals.quad.draw();
781
835
  pingPong = (pingPong + 1) % 2;
782
836
  }
@@ -811,9 +865,6 @@ const THREAD_GROUP_SIZE = 16;
811
865
  this._postfft2BindGroup.setTexture('ifft3', ifftTextures[3], nearestRepeatSampler);
812
866
  this._postfft2BindGroup.setTexture('ifft4', ifftTextures[4], nearestRepeatSampler);
813
867
  this._postfft2BindGroup.setTexture('ifft5', ifftTextures[5], nearestRepeatSampler);
814
- if (device.type === 'webgl') {
815
- this._postfft2BindGroup.setValue('ifftTexSize', new Vector2(ifftTextures[0].width, ifftTextures[0].height));
816
- }
817
868
  FFTWaveGenerator._globals.quad.draw();
818
869
  }
819
870
  }
@@ -829,18 +880,12 @@ const THREAD_GROUP_SIZE = 16;
829
880
  this._postfft2BindGroup4.setTexture('ifft1', ifftTextures[1], nearestRepeatSampler);
830
881
  this._postfft2BindGroup4.setTexture('ifft2', ifftTextures[2], nearestRepeatSampler);
831
882
  this._postfft2BindGroup4.setTexture('ifft3', ifftTextures[3], nearestRepeatSampler);
832
- if (device.type === 'webgl') {
833
- this._postfft2BindGroup4.setValue('ifftTexSize', new Vector2(ifftTextures[0].width, ifftTextures[0].height));
834
- }
835
883
  FFTWaveGenerator._globals.quad.draw();
836
884
  device.setFramebuffer(instanceData.postIfft2Framebuffer2);
837
885
  device.setProgram(FFTWaveGenerator._globals.programs.postfft2Program2);
838
886
  device.setBindGroup(0, this._postfft2BindGroup2);
839
887
  this._postfft2BindGroup2.setTexture('ifft4', ifftTextures[4], nearestRepeatSampler);
840
888
  this._postfft2BindGroup2.setTexture('ifft5', ifftTextures[5], nearestRepeatSampler);
841
- if (device.type === 'webgl') {
842
- this._postfft2BindGroup2.setValue('ifftTexSize', new Vector2(ifftTextures[0].width, ifftTextures[0].height));
843
- }
844
889
  FFTWaveGenerator._globals.quad.draw();
845
890
  }
846
891
  /** {@inheritDoc WaveGenerator.setupUniforms} */ setupUniforms(scope, uniformGroup) {
@@ -858,6 +903,64 @@ const THREAD_GROUP_SIZE = 16;
858
903
  scope.sx_sz_dxdx_dzdz2 = pb.tex2D().uniform(uniformGroup);
859
904
  }
860
905
  scope.foamParams = pb.vec2().uniform(uniformGroup);
906
+ scope.slopeVar0 = pb.vec4().uniform(uniformGroup);
907
+ scope.slopeVar1 = pb.vec4().uniform(uniformGroup);
908
+ scope.slopeVar2 = pb.vec4().uniform(uniformGroup);
909
+ scope.slopeRetained = pb.vec4[6]().uniform(uniformGroup);
910
+ }
911
+ /**
912
+ * Mip level each cascade is read at by a pixel with screen derivatives
913
+ * `xzGrad` of its xz, as anisotropic filtering picks it: from the shorter
914
+ * axis of the pixel, or the longer over the anisotropy where that is more.
915
+ * @internal
916
+ */ cascadeLods(scope, xzGrad) {
917
+ const pb = scope.$builder;
918
+ pb.func('fftCascadeLods', [
919
+ pb.vec4('xzGrad')
920
+ ], function() {
921
+ this.$l.lx = pb.mul(pb.length(this.xzGrad.xy), SLOPE_FILTER_SCALE);
922
+ this.$l.ly = pb.mul(pb.length(this.xzGrad.zw), SLOPE_FILTER_SCALE);
923
+ this.$l.fp = pb.max(pb.max(pb.min(this.lx, this.ly), pb.div(pb.max(this.lx, this.ly), SLOPE_MAX_ANISOTROPY)), 1e-6);
924
+ this.$l.texel = pb.vec3(this.slopeVar0.w, this.slopeVar1.w, this.slopeVar2.w);
925
+ this.$return(pb.max(pb.log2(pb.div(pb.vec3(this.fp), this.texel)), pb.vec3(0)));
926
+ });
927
+ return scope.fftCascadeLods(xzGrad);
928
+ }
929
+ /** Trilinear, anisotropic sampler of the slope mips. @internal */ static getSlopeSampler() {
930
+ const globals = FFTWaveGenerator._globals;
931
+ if (!globals.slopeSampler) {
932
+ globals.slopeSampler = getDevice().createSampler({
933
+ addressU: 'repeat',
934
+ addressV: 'repeat',
935
+ magFilter: 'linear',
936
+ minFilter: 'linear',
937
+ mipFilter: 'linear',
938
+ maxAnisotropy: SLOPE_MAX_ANISOTROPY
939
+ });
940
+ }
941
+ return globals.slopeSampler;
942
+ }
943
+ /** {@inheritDoc WaveGenerator.calcUnresolvedSlopeVariance} */ calcUnresolvedSlopeVariance(scope, xzGrad) {
944
+ const pb = scope.$builder;
945
+ const that = this;
946
+ // Share of a cascade's slope variance its mip level keeps, linear between levels
947
+ pb.func('fftSlopeRetained', [
948
+ pb.float('lod'),
949
+ pb.vec4('lo'),
950
+ pb.vec4('hi')
951
+ ], function() {
952
+ this.$l.hatLo = pb.max(pb.sub(pb.vec4(1), pb.abs(pb.sub(pb.vec4(this.lod), pb.vec4(1, 2, 3, 4)))), pb.vec4(0));
953
+ this.$l.hatHi = pb.max(pb.sub(pb.vec4(1), pb.abs(pb.sub(pb.vec4(this.lod), pb.vec4(5, 6, 7, 8)))), pb.vec4(0));
954
+ this.$return(pb.add(pb.max(pb.sub(1, this.lod), 0), pb.dot(this.hatLo, this.lo), pb.mul(pb.dot(this.hatHi, this.hi), pb.clamp(pb.sub(SLOPE_LOD_LEVELS + 1, this.lod), 0, 1))));
955
+ });
956
+ pb.func('fftUnresolvedSlopeVariance', [
957
+ pb.vec4('xzGrad')
958
+ ], function() {
959
+ this.$l.lod = that.cascadeLods(this, this.xzGrad);
960
+ this.$l.lost = pb.sub(pb.vec3(1), pb.vec3(this.fftSlopeRetained(this.lod.x, this.slopeRetained.at(0), this.slopeRetained.at(1)), this.fftSlopeRetained(this.lod.y, this.slopeRetained.at(2), this.slopeRetained.at(3)), this.fftSlopeRetained(this.lod.z, this.slopeRetained.at(4), this.slopeRetained.at(5))));
961
+ this.$return(pb.add(pb.mul(this.slopeVar0.xyz, this.lost.x), pb.mul(this.slopeVar1.xyz, this.lost.y), pb.mul(this.slopeVar2.xyz, this.lost.z)));
962
+ });
963
+ return scope.fftUnresolvedSlopeVariance(xzGrad);
861
964
  }
862
965
  /** {@inheritDoc WaveGenerator.calcVertexPositionAndNormal} */ calcVertexPositionAndNormal(scope, inPos, outPos, outNormal) {
863
966
  const pb = scope.$builder;
@@ -907,29 +1010,15 @@ const THREAD_GROUP_SIZE = 16;
907
1010
  this.$l.sx = pb.add(this._sx_sz_dxdx_dzdz0.x, this._sx_sz_dxdx_dzdz1.x, this._sx_sz_dxdx_dzdz2.x);
908
1011
  this.$l.sz = pb.add(this._sx_sz_dxdx_dzdz0.y, this._sx_sz_dxdx_dzdz1.y, this._sx_sz_dxdx_dzdz2.y);
909
1012
  this.$l.dxdx_dzdz = pb.add(pb.mul(this._sx_sz_dxdx_dzdz0.zw, this.croppinesses.x), pb.mul(this._sx_sz_dxdx_dzdz1.zw, this.croppinesses.y), pb.mul(this._sx_sz_dxdx_dzdz2.zw, this.croppinesses.z));
910
- // The normal of the displaced surface. Writing the Jacobian of the
911
- // horizontal displacement as [[A, C], [C, F]] with A = 1 + croppiness*d2x,
912
- // F = 1 + croppiness*d2z, C = croppiness*dxdz and determinant
913
- // J = A*F - C*C, the cross product of the two tangents is
1013
+ // Normal of the displaced surface. With the Jacobian of the horizontal
1014
+ // displacement [[A, C], [C, F]], A = 1 + croppiness*d2x, F = 1 + croppiness*d2z,
1015
+ // C = croppiness*dxdz and J = A*F - C*C, the tangents' cross product is
914
1016
  //
915
1017
  // N ~ ( -sx * F, J, -sz * A )
916
1018
  //
917
- // The determinant never reaches the horizontal components: dividing the
918
- // whole vector by A*F recovers the per-axis slope correction -sx/A, -sz/F,
919
- // which is what this used to do, plus the J/(A*F) = 1 - C^2/(A*F) term on
920
- // the y axis that the earlier form dropped. Putting J on the horizontal
921
- // components instead (a form this briefly had) multiplies the whole normal
922
- // by sign(J), so they jump as J crosses zero - a hard seam, not a fold.
923
- //
924
- // The y component takes the magnitude. J goes negative where the choppy
925
- // displacement folds the sheet over on itself - the same condition the
926
- // foam mask reads - and the cross-product normal there points down, into
927
- // the water. That is geometrically true of the overturned sheet and
928
- // geometrically useless to a renderer that lights the surface from above:
929
- // a downward normal loses the sun, samples the sky's lower hemisphere for
930
- // the irradiance and drives the view-facing term negative, which between
931
- // them painted the fold black. The shading treats the water interface as
932
- // upward-facing wherever it is, and the foam owns the folded band.
1019
+ // J must stay off the horizontal components, or the normal flips with
1020
+ // sign(J). The y component takes |J|: where the sheet folds (J < 0, the
1021
+ // foam band) the true normal points down, which the shading cannot light.
933
1022
  let dxdzSamples;
934
1023
  if (that._useComputeShader) {
935
1024
  dxdzSamples = pb.vec3(pb.textureArraySampleLevel(this.dataTexture, this.uv0, 0, 0).w, pb.textureArraySampleLevel(this.dataTexture, this.uv1, 2, 0).w, pb.textureArraySampleLevel(this.dataTexture, this.uv2, 4, 0).w);
@@ -945,7 +1034,7 @@ const THREAD_GROUP_SIZE = 16;
945
1034
  });
946
1035
  return scope.calcFragmentNormal(xz);
947
1036
  }
948
- /** {@inheritDoc WaveGenerator.calcFragmentNormalAndFoam} */ calcFragmentNormalAndFoam(scope, xz) {
1037
+ /** {@inheritDoc WaveGenerator.calcFragmentNormalAndFoam} */ calcFragmentNormalAndFoam(scope, xz, _vertexNormal, _foamSample, xzGrad) {
949
1038
  const pb = scope.$builder;
950
1039
  const that = this;
951
1040
  pb.func('jacobian', [
@@ -963,58 +1052,55 @@ const THREAD_GROUP_SIZE = 16;
963
1052
  ], function() {
964
1053
  this.$return(pb.sub(pb.mul(this.jacobian.x, this.jacobian.w), pb.mul(this.jacobian.y, this.jacobian.z)));
965
1054
  });
966
- pb.func('calcNormalAndFoam', [
1055
+ const params = xzGrad ? [
1056
+ pb.vec2('xz'),
1057
+ pb.vec4('xzGrad')
1058
+ ] : [
967
1059
  pb.vec2('xz')
968
- ], function() {
1060
+ ];
1061
+ const funcName = xzGrad ? 'calcNormalAndFoamF' : 'calcNormalAndFoam';
1062
+ pb.func(funcName, params, function() {
969
1063
  this.$l.uv0 = pb.div(this.xz, this.sizes.x);
970
1064
  this.$l.uv1 = pb.div(this.xz, this.sizes.y);
971
1065
  this.$l.uv2 = pb.div(this.xz, this.sizes.z);
972
- if (that._useComputeShader) {
973
- this.$l._sx_sz_dxdx_dzdz0 = pb.textureArraySampleLevel(this.dataTexture, this.uv0, 1, 0);
974
- this.$l._sx_sz_dxdx_dzdz1 = pb.textureArraySampleLevel(this.dataTexture, this.uv1, 3, 0);
975
- this.$l._sx_sz_dxdx_dzdz2 = pb.textureArraySampleLevel(this.dataTexture, this.uv2, 5, 0);
976
- } else {
977
- this.$l._sx_sz_dxdx_dzdz0 = pb.textureSampleLevel(this.sx_sz_dxdx_dzdz0, this.uv0, 0);
978
- this.$l._sx_sz_dxdx_dzdz1 = pb.textureSampleLevel(this.sx_sz_dxdx_dzdz1, this.uv1, 0);
979
- this.$l._sx_sz_dxdx_dzdz2 = pb.textureSampleLevel(this.sx_sz_dxdx_dzdz2, this.uv2, 0);
980
- }
1066
+ // Slopes and Jacobian filtered down to the pixel: each cascade read with
1067
+ // the screen derivatives of its texture coordinates, trilinear and
1068
+ // anisotropic, so the waves too short for the pixel average out rather
1069
+ // than alias into speckle
1070
+ const sample = (tex, layer, uv, size)=>{
1071
+ if (!xzGrad) {
1072
+ return that._useComputeShader ? pb.textureArraySampleLevel(this.dataTexture, this[uv], layer, 0) : pb.textureSampleLevel(this[tex], this[uv], 0);
1073
+ }
1074
+ const ddx = pb.mul(this.xzGrad.xy, pb.div(SLOPE_FILTER_SCALE, this.sizes[size]));
1075
+ const ddy = pb.mul(this.xzGrad.zw, pb.div(SLOPE_FILTER_SCALE, this.sizes[size]));
1076
+ return that._useComputeShader ? pb.textureArraySampleGrad(this.dataTexture, this[uv], layer, ddx, ddy) : pb.textureSampleGrad(this[tex], this[uv], ddx, ddy);
1077
+ };
1078
+ this.$l._sx_sz_dxdx_dzdz0 = sample('sx_sz_dxdx_dzdz0', 1, 'uv0', 'x');
1079
+ this.$l._sx_sz_dxdx_dzdz1 = sample('sx_sz_dxdx_dzdz1', 3, 'uv1', 'y');
1080
+ this.$l._sx_sz_dxdx_dzdz2 = sample('sx_sz_dxdx_dzdz2', 5, 'uv2', 'z');
981
1081
  this.$l.sx = pb.add(this._sx_sz_dxdx_dzdz0.x, this._sx_sz_dxdx_dzdz1.x, this._sx_sz_dxdx_dzdz2.x);
982
1082
  this.$l.sz = pb.add(this._sx_sz_dxdx_dzdz0.y, this._sx_sz_dxdx_dzdz1.y, this._sx_sz_dxdx_dzdz2.y);
983
1083
  this.$l.dxdx_dzdz = pb.add(pb.mul(this._sx_sz_dxdx_dzdz0.zw, this.croppinesses.x), pb.mul(this._sx_sz_dxdx_dzdz1.zw, this.croppinesses.y), pb.mul(this._sx_sz_dxdx_dzdz2.zw, this.croppinesses.z));
984
- // foam
985
- this.$l.dxdx_dzdz0 = this._sx_sz_dxdx_dzdz0.zw;
986
- this.$l.dxdx_dzdz1 = this._sx_sz_dxdx_dzdz1.zw;
987
- this.$l.dxdx_dzdz2 = this._sx_sz_dxdx_dzdz2.zw;
988
- if (that._useComputeShader) {
989
- this.$l.dxdz0 = pb.textureArraySampleLevel(this.dataTexture, this.uv0, 0, 0).w;
990
- this.$l.dxdz1 = pb.textureArraySampleLevel(this.dataTexture, this.uv1, 2, 0).w;
991
- this.$l.dxdz2 = pb.textureArraySampleLevel(this.dataTexture, this.uv2, 4, 0).w;
992
- } else {
993
- this.$l.dxdz0 = pb.textureSampleLevel(this.dx_hy_dz_dxdz0, this.uv0, 0).w;
994
- this.$l.dxdz1 = pb.textureSampleLevel(this.dx_hy_dz_dxdz1, this.uv1, 0).w;
995
- this.$l.dxdz2 = pb.textureSampleLevel(this.dx_hy_dz_dxdz2, this.uv2, 0).w;
996
- }
1084
+ this.$l.dxdz0 = sample('dx_hy_dz_dxdz0', 0, 'uv0', 'x').w;
1085
+ this.$l.dxdz1 = sample('dx_hy_dz_dxdz1', 2, 'uv1', 'y').w;
1086
+ this.$l.dxdz2 = sample('dx_hy_dz_dxdz2', 4, 'uv2', 'z').w;
997
1087
  this.$l.dxdz = pb.add(pb.mul(this.dxdz0, this.croppinesses.x), pb.mul(this.dxdz1, this.croppinesses.y), pb.mul(this.dxdz2, this.croppinesses.z));
998
1088
  this.$l.jacobian4 = this.jacobian(this.dxdx_dzdz.x, this.dxdz, this.dxdx_dzdz.y);
999
1089
  this.$l.val = this.det(this.jacobian4);
1000
- // The normal of the displaced surface, from the same Jacobian the foam
1001
- // reads: N ~ (-sx*F, J, -sz*A), with A and F the diagonals the helper
1002
- // packs into x and w. Sharing the determinant keeps the shading normal and
1003
- // the foam mask describing the same fold, and taking its magnitude keeps
1004
- // the normal upward-facing there - see calcFragmentNormal for why the sign
1005
- // cannot be used and why the horizontals take A and F rather than J.
1090
+ // Same Jacobian as the foam reads: N ~ (-sx*F, |J|, -sz*A), with A and F
1091
+ // packed into x and w. See calcFragmentNormal.
1006
1092
  this.$l.normal = pb.normalize(pb.vec3(pb.neg(pb.mul(this.sx, this.jacobian4.w)), pb.abs(this.val), pb.neg(pb.mul(this.sz, this.jacobian4.x))));
1007
1093
  this.$l.foam = pb.abs(pb.pow(pb.neg(pb.min(0, pb.sub(this.val, this.foamParams.x))), this.foamParams.y));
1008
1094
  this.$return(pb.vec4(this.normal, this.foam));
1009
1095
  });
1010
- return scope.calcNormalAndFoam(xz);
1096
+ return xzGrad ? scope[funcName](xz, xzGrad) : scope[funcName](xz);
1011
1097
  }
1012
1098
  /** {@inheritDoc WaveGenerator.isOk} */ isOk() {
1013
1099
  return this._renderMode !== RENDER_NONE;
1014
1100
  }
1015
1101
  /** {@inheritDoc WaveGenerator.applyWaterBindGroup} */ applyWaterBindGroup(bindGroup) {
1016
1102
  const instanceData = this.getInstanceData();
1017
- const linearRepeatSampler = fetchSampler('repeat_linear_nomip');
1103
+ const linearRepeatSampler = FFTWaveGenerator.getSlopeSampler();
1018
1104
  if (this._useComputeShader) {
1019
1105
  bindGroup.setTexture('dataTexture', instanceData.dataTextures, linearRepeatSampler);
1020
1106
  } else {
@@ -1029,6 +1115,10 @@ const THREAD_GROUP_SIZE = 16;
1029
1115
  bindGroup.setValue('foamParams', this._params.foamParams);
1030
1116
  bindGroup.setValue('sizes', this._sizes);
1031
1117
  bindGroup.setValue('croppinesses', this._croppinesses);
1118
+ bindGroup.setValue('slopeVar0', this._slopeVariances[0]);
1119
+ bindGroup.setValue('slopeVar1', this._slopeVariances[1]);
1120
+ bindGroup.setValue('slopeVar2', this._slopeVariances[2]);
1121
+ bindGroup.setValue('slopeRetained', this._slopeRetained);
1032
1122
  }
1033
1123
  /** {@inheritDoc WaveGenerator.calcClipmapTileAABB} */ calcClipmapTileAABB(minX, maxX, minZ, maxZ, y, outAABB) {
1034
1124
  const disturb = Math.max(Math.abs(this.wind.x), Math.abs(this.wind.y), 2);