@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
@@ -6,29 +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
- maxWave: 100
28
+ croppiness: -1.5
18
29
  },
19
30
  {
20
- size: 100.0,
21
31
  strength: 0.4,
22
- croppiness: -1.2,
23
- minWave: 0,
24
- maxWave: 100
32
+ croppiness: -1.2
25
33
  },
26
34
  {
27
- size: 15,
28
- strength: 0.2,
29
- croppiness: -0.5,
30
- minWave: 0,
31
- maxWave: 7
35
+ strength: 0.4,
36
+ croppiness: -0.5
32
37
  }
33
38
  ],
34
39
  resolution: 256,
@@ -42,6 +47,22 @@ const RENDER_NONE = 0;
42
47
  const RENDER_NORMAL = 1;
43
48
  const RENDER_TWO_PASS = 2;
44
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;
45
66
  /**
46
67
  * This class generates a 2D ocean field using the Fast Fourier Transform (FFT) algorithm.
47
68
  * @public
@@ -72,6 +93,8 @@ const THREAD_GROUP_SIZE = 16;
72
93
  _instanceData;
73
94
  _ifftTextures;
74
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;
75
98
  _paramsChanged;
76
99
  _version;
77
100
  _resolutionChanged;
@@ -86,7 +109,7 @@ const THREAD_GROUP_SIZE = 16;
86
109
  super();
87
110
  const device = getDevice();
88
111
  const renderTargetFloat16 = device.getDeviceCaps().textureCaps.supportHalfFloatColorBuffer;
89
- const maxDrawBuffers = /*device.type !== 'webgl' && */ renderTargetFloat16 ? device.getDeviceCaps().framebufferCaps.maxDrawBuffers : 0;
112
+ const maxDrawBuffers = renderTargetFloat16 ? device.getDeviceCaps().framebufferCaps.maxDrawBuffers : 0;
90
113
  this._textureFormat = 'rgba16f';
91
114
  this._h0TextureFormat = 'rgba16f';
92
115
  this._dataTextureFormat = 'rgba16f';
@@ -173,6 +196,12 @@ const THREAD_GROUP_SIZE = 16;
173
196
  new Vector4(),
174
197
  new Vector4()
175
198
  ];
199
+ this._slopeVariances = [
200
+ new Vector4(),
201
+ new Vector4(),
202
+ new Vector4()
203
+ ];
204
+ this._slopeRetained = new Float32Array(6 * 4);
176
205
  this._updateRenderStates = getDevice().createRenderStateSet();
177
206
  this._updateRenderStates.useRasterizerState().setCullMode('none');
178
207
  this._updateRenderStates.useDepthState().enableTest(false).enableWrite(false);
@@ -186,17 +215,7 @@ const THREAD_GROUP_SIZE = 16;
186
215
  clone() {
187
216
  return new FFTWaveGenerator(this._params);
188
217
  }
189
- /*
190
- get params() {
191
- return this._params;
192
- }
193
- set params(val: OceanFieldBuildParams) {
194
- if (val && val !== this._params) {
195
- this._params = val;
196
- this.paramsChanged();
197
- }
198
- }
199
- */ paramsChanged() {
218
+ paramsChanged() {
200
219
  this._paramsChanged = true;
201
220
  this._version++;
202
221
  }
@@ -237,18 +256,18 @@ const THREAD_GROUP_SIZE = 16;
237
256
  this.paramsChanged();
238
257
  }
239
258
  }
240
- /** Gets the wave length for the specified cascade */ getWaveLength(cascade) {
241
- return this._params.cascades[cascade].size;
242
- }
243
259
  /**
244
- * 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.
245
265
  * @param cascade - The cascade index
246
- * @param length - The new wave length for the specified cascade
247
- */ setWaveLength(cascade, length) {
248
- if (this._params.cascades[cascade].size !== length) {
249
- this._params.cascades[cascade].size = length;
250
- this.paramsChanged();
251
- }
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);
252
271
  }
253
272
  /** Gets the wave strength for the specified cascade */ getWaveStrength(cascade) {
254
273
  return this._params.cascades[cascade].strength;
@@ -340,12 +359,19 @@ const THREAD_GROUP_SIZE = 16;
340
359
  this._h0BindGroup.setValue('resolution', this._params.resolution);
341
360
  this._h0BindGroup.setValue('wind', this._params.wind);
342
361
  this._h0BindGroup.setValue('alignment', this._params.alignment);
343
- for(let i = 0; i < this._params.cascades.length; i++){
344
- this._cascades[i].x = this._params.cascades[i].size;
345
- this._cascades[i].y = this._params.cascades[i].strength * 0.081 / (this._params.cascades[i].size * this._params.cascades[i].size);
346
- this._cascades[i].z = 2 * Math.PI / this._params.cascades[i].maxWave;
347
- 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;
348
373
  }
374
+ this.computeSlopeVariances();
349
375
  this._h0BindGroup.setValue('cascade0', this._cascades[0]);
350
376
  this._h0BindGroup.setValue('cascade1', this._cascades[1]);
351
377
  this._h0BindGroup.setValue('cascade2', this._cascades[2]);
@@ -358,33 +384,90 @@ const THREAD_GROUP_SIZE = 16;
358
384
  FFTWaveGenerator._globals.quad.draw();
359
385
  }
360
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
+ }
361
451
  /** @internal */ getNoiseTexture(size, randomSeed) {
362
452
  const device = getDevice();
363
- let tex = FFTWaveGenerator._globals.noiseTextures.get(size);
453
+ // Keyed on the seed as well as the size: both select the noise.
454
+ const key = `${size}:${randomSeed}`;
455
+ let tex = FFTWaveGenerator._globals.noiseTextures.get(key);
364
456
  if (!tex) {
365
- tex = device.createTexture2D(device.type === 'webgl' ? 'rgba32f' : 'rg32f', size, size, {
457
+ tex = device.createTexture2D('rg32f', size, size, {
366
458
  mipmapping: false
367
459
  });
368
- tex.name = `noiseTex${size}`;
369
- tex.update(this.getNoise2d(size, randomSeed, device.type === 'webgl'), 0, 0, size, size);
370
- FFTWaveGenerator._globals.noiseTextures.set(size, tex);
460
+ tex.name = `noiseTex${size}_${randomSeed}`;
461
+ tex.update(this.getNoise2d(size, randomSeed), 0, 0, size, size);
462
+ FFTWaveGenerator._globals.noiseTextures.set(key, tex);
371
463
  }
372
464
  return tex;
373
465
  }
374
- /** @internal */ getNoise2d(size, randomSeed, rgba) {
466
+ /** @internal */ getNoise2d(size, randomSeed) {
375
467
  const rand = new PRNG(randomSeed);
376
- if (rgba) {
377
- const array = new Float32Array(size * size * 4);
378
- for(let i = 0; i < size * size; i++){
379
- array[i * 4 + 0] = rand.get();
380
- array[i * 4 + 1] = rand.get();
381
- }
382
- return array;
383
- } else {
384
- return Float32Array.from([
385
- ...Array(size * size * 2)
386
- ].map(()=>rand.get()));
387
- }
468
+ return Float32Array.from([
469
+ ...Array(size * size * 2)
470
+ ].map(()=>rand.get()));
388
471
  }
389
472
  /** @internal */ reverseBits(v, width) {
390
473
  return parseInt(v.toString(2).padStart(width, '0').split('').reverse().join(''), 2);
@@ -430,7 +513,7 @@ const THREAD_GROUP_SIZE = 16;
430
513
  if (!this._instanceData) {
431
514
  const device = getDevice();
432
515
  const h0Textures = this.createNTextures(device, this._h0TextureFormat, this._params.resolution, 3, 'Water-h0', false);
433
- 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);
434
517
  const spectrumTextures = this.createNTextures(device, this._textureFormat, this._params.resolution, 6, 'Water-spectrum', true);
435
518
  const pingpongTextures = this.createNTextures(device, this._textureFormat, this._params.resolution, 6, 'Water-pingpong', false);
436
519
  this._instanceData = {
@@ -452,17 +535,17 @@ const THREAD_GROUP_SIZE = 16;
452
535
  }
453
536
  return this._instanceData;
454
537
  }
455
- /** @internal */ createNTextures(device, format, size, num, name, linear) {
538
+ /** @internal */ createNTextures(device, format, size, num, name, linear, mipmapping = false) {
456
539
  const options = {
457
540
  samplerOptions: {
458
541
  minFilter: linear ? 'linear' : 'nearest',
459
542
  magFilter: linear ? 'linear' : 'nearest',
460
- mipFilter: 'none',
543
+ mipFilter: mipmapping ? 'linear' : 'none',
461
544
  addressU: 'repeat',
462
545
  addressV: 'repeat'
463
546
  },
464
547
  writable: !!this._useComputeShader,
465
- mipmapping: false
548
+ mipmapping
466
549
  };
467
550
  if (this._useComputeShader) {
468
551
  const tex = device.createTexture2DArray(format, size, size, num, options);
@@ -491,7 +574,7 @@ const THREAD_GROUP_SIZE = 16;
491
574
  this._resolutionChanged = false;
492
575
  this._paramsChanged = false;
493
576
  for(let i = 0; i < 3; i++){
494
- this._sizes[i] = this._params.cascades[i].size;
577
+ this._sizes[i] = this._cascades[i].x;
495
578
  this._croppinesses[i] = this._params.cascades[i].croppiness;
496
579
  }
497
580
  if (this._renderMode === RENDER_NORMAL) {
@@ -503,6 +586,13 @@ const THREAD_GROUP_SIZE = 16;
503
586
  this.ifft2TwoPass();
504
587
  this.postIfft2TwoPass();
505
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
+ }
506
596
  device.popDeviceStates();
507
597
  }
508
598
  /** {@inheritDoc WaveGenerator.needUpdate} */ needUpdate() {
@@ -552,9 +642,6 @@ const THREAD_GROUP_SIZE = 16;
552
642
  this._hkBindGroup.setTexture('h0Texture0', h0Textures[0], nearestRepeatSampler);
553
643
  this._hkBindGroup.setTexture('h0Texture1', h0Textures[1], nearestRepeatSampler);
554
644
  this._hkBindGroup.setTexture('h0Texture2', h0Textures[2], nearestRepeatSampler);
555
- if (device.type === 'webgl') {
556
- this._hkBindGroup.setValue('h0TexSize', new Vector2(h0Textures[0].width, h0Textures[0].height));
557
- }
558
645
  device.setFramebuffer(instanceData.spectrumFramebuffer);
559
646
  FFTWaveGenerator._globals.quad.draw();
560
647
  }
@@ -571,9 +658,6 @@ const THREAD_GROUP_SIZE = 16;
571
658
  this._hkBindGroup4.setTexture('h0Texture0', h0Textures[0], nearestRepeatSampler);
572
659
  this._hkBindGroup4.setTexture('h0Texture1', h0Textures[1], nearestRepeatSampler);
573
660
  this._hkBindGroup4.setValue('t', time);
574
- if (device.type === 'webgl') {
575
- this._hkBindGroup4.setValue('h0TexSize', new Vector2(h0Textures[0].width, h0Textures[0].height));
576
- }
577
661
  device.setFramebuffer(instanceData.spectrumFramebuffer4);
578
662
  FFTWaveGenerator._globals.quad.draw();
579
663
  device.setProgram(FFTWaveGenerator._globals.programs.hkProgram2);
@@ -582,9 +666,6 @@ const THREAD_GROUP_SIZE = 16;
582
666
  this._hkBindGroup2.setValue('sizes', this._sizes);
583
667
  this._hkBindGroup2.setTexture('h0Texture2', h0Textures[2], nearestRepeatSampler);
584
668
  this._hkBindGroup2.setValue('t', time);
585
- if (device.type === 'webgl') {
586
- this._hkBindGroup2.setValue('h0TexSize', new Vector2(h0Textures[0].width, h0Textures[0].height));
587
- }
588
669
  device.setFramebuffer(instanceData.spectrumFramebuffer2);
589
670
  FFTWaveGenerator._globals.quad.draw();
590
671
  }
@@ -625,9 +706,6 @@ const THREAD_GROUP_SIZE = 16;
625
706
  this._fft2hBindGroup.setTexture('spectrum3', pingPongTexture[3], nearestRepeatSampler);
626
707
  this._fft2hBindGroup.setTexture('spectrum4', pingPongTexture[4], nearestRepeatSampler);
627
708
  this._fft2hBindGroup.setTexture('spectrum5', pingPongTexture[5], nearestRepeatSampler);
628
- if (device.type === 'webgl') {
629
- this._fft2hBindGroup.setValue('texSize', new Vector4(pingPongTexture[0].width, pingPongTexture[0].height, butterflyTex.width, butterflyTex.height));
630
- }
631
709
  FFTWaveGenerator._globals.quad.draw();
632
710
  }
633
711
  pingPong = 1 - pingPong; //(pingPong + 1) % 2;
@@ -651,9 +729,6 @@ const THREAD_GROUP_SIZE = 16;
651
729
  this._fft2vBindGroup.setTexture('spectrum3', pingPongTexture[3], nearestRepeatSampler);
652
730
  this._fft2vBindGroup.setTexture('spectrum4', pingPongTexture[4], nearestRepeatSampler);
653
731
  this._fft2vBindGroup.setTexture('spectrum5', pingPongTexture[5], nearestRepeatSampler);
654
- if (device.type === 'webgl') {
655
- this._fft2vBindGroup.setValue('texSize', new Vector4(pingPongTexture[0].width, pingPongTexture[0].height, butterflyTex.width, butterflyTex.height));
656
- }
657
732
  FFTWaveGenerator._globals.quad.draw();
658
733
  }
659
734
  pingPong = 1 - pingPong;
@@ -723,9 +798,6 @@ const THREAD_GROUP_SIZE = 16;
723
798
  fft2hBindGroup4.setTexture('spectrum1', pingPongTextures[pingPong][1], nearestRepeatSampler);
724
799
  fft2hBindGroup4.setTexture('spectrum2', pingPongTextures[pingPong][2], nearestRepeatSampler);
725
800
  fft2hBindGroup4.setTexture('spectrum3', pingPongTextures[pingPong][3], nearestRepeatSampler);
726
- if (device.type === 'webgl') {
727
- fft2hBindGroup4.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
728
- }
729
801
  FFTWaveGenerator._globals.quad.draw();
730
802
  device.setFramebuffer(pingPongFramebuffers2[pingPong]);
731
803
  device.setProgram(FFTWaveGenerator._globals.programs.fft2hProgram2);
@@ -735,9 +807,6 @@ const THREAD_GROUP_SIZE = 16;
735
807
  fft2hBindGroup2.setValue('phase', phase);
736
808
  fft2hBindGroup2.setTexture('spectrum4', pingPongTextures[pingPong][4], nearestRepeatSampler);
737
809
  fft2hBindGroup2.setTexture('spectrum5', pingPongTextures[pingPong][5], nearestRepeatSampler);
738
- if (device.type === 'webgl') {
739
- fft2hBindGroup2.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
740
- }
741
810
  FFTWaveGenerator._globals.quad.draw();
742
811
  pingPong = (pingPong + 1) % 2;
743
812
  }
@@ -753,9 +822,6 @@ const THREAD_GROUP_SIZE = 16;
753
822
  fft2vBindGroup4.setTexture('spectrum1', pingPongTextures[pingPong][1], nearestRepeatSampler);
754
823
  fft2vBindGroup4.setTexture('spectrum2', pingPongTextures[pingPong][2], nearestRepeatSampler);
755
824
  fft2vBindGroup4.setTexture('spectrum3', pingPongTextures[pingPong][3], nearestRepeatSampler);
756
- if (device.type === 'webgl') {
757
- fft2vBindGroup4.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
758
- }
759
825
  FFTWaveGenerator._globals.quad.draw();
760
826
  device.setFramebuffer(pingPongFramebuffers2[pingPong]);
761
827
  device.setProgram(FFTWaveGenerator._globals.programs.fft2vProgram2);
@@ -765,9 +831,6 @@ const THREAD_GROUP_SIZE = 16;
765
831
  fft2vBindGroup2.setValue('phase', phase);
766
832
  fft2vBindGroup2.setTexture('spectrum4', pingPongTextures[pingPong][4], nearestRepeatSampler);
767
833
  fft2vBindGroup2.setTexture('spectrum5', pingPongTextures[pingPong][5], nearestRepeatSampler);
768
- if (device.type === 'webgl') {
769
- fft2vBindGroup2.setValue('texSize', new Vector4(pingPongTextures[pingPong][0].width, pingPongTextures[pingPong][0].height, butterflyTex.width, butterflyTex.height));
770
- }
771
834
  FFTWaveGenerator._globals.quad.draw();
772
835
  pingPong = (pingPong + 1) % 2;
773
836
  }
@@ -789,7 +852,6 @@ const THREAD_GROUP_SIZE = 16;
789
852
  const nearestRepeatSampler = fetchSampler('repeat_nearest_nomip');
790
853
  device.setProgram(FFTWaveGenerator._globals.programs.postfft2Program);
791
854
  device.setBindGroup(0, this._postfft2BindGroup);
792
- this._postfft2BindGroup.setValue('N2', this._params.resolution * this._params.resolution);
793
855
  if (this._useComputeShader) {
794
856
  this._postfft2BindGroup.setTexture('output', instanceData.dataTextures);
795
857
  this._postfft2BindGroup.setTexture('ifft', this._ifftTextures, nearestRepeatSampler);
@@ -803,9 +865,6 @@ const THREAD_GROUP_SIZE = 16;
803
865
  this._postfft2BindGroup.setTexture('ifft3', ifftTextures[3], nearestRepeatSampler);
804
866
  this._postfft2BindGroup.setTexture('ifft4', ifftTextures[4], nearestRepeatSampler);
805
867
  this._postfft2BindGroup.setTexture('ifft5', ifftTextures[5], nearestRepeatSampler);
806
- if (device.type === 'webgl') {
807
- this._postfft2BindGroup.setValue('ifftTexSize', new Vector2(ifftTextures[0].width, ifftTextures[0].height));
808
- }
809
868
  FFTWaveGenerator._globals.quad.draw();
810
869
  }
811
870
  }
@@ -817,24 +876,16 @@ const THREAD_GROUP_SIZE = 16;
817
876
  device.setProgram(FFTWaveGenerator._globals.programs.postfft2Program4);
818
877
  device.setBindGroup(0, this._postfft2BindGroup4);
819
878
  const ifftTextures = this._ifftTextures;
820
- this._postfft2BindGroup4.setValue('N2', this._params.resolution * this._params.resolution);
821
879
  this._postfft2BindGroup4.setTexture('ifft0', ifftTextures[0], nearestRepeatSampler);
822
880
  this._postfft2BindGroup4.setTexture('ifft1', ifftTextures[1], nearestRepeatSampler);
823
881
  this._postfft2BindGroup4.setTexture('ifft2', ifftTextures[2], nearestRepeatSampler);
824
882
  this._postfft2BindGroup4.setTexture('ifft3', ifftTextures[3], nearestRepeatSampler);
825
- if (device.type === 'webgl') {
826
- this._postfft2BindGroup4.setValue('ifftTexSize', new Vector2(ifftTextures[0].width, ifftTextures[0].height));
827
- }
828
883
  FFTWaveGenerator._globals.quad.draw();
829
884
  device.setFramebuffer(instanceData.postIfft2Framebuffer2);
830
885
  device.setProgram(FFTWaveGenerator._globals.programs.postfft2Program2);
831
886
  device.setBindGroup(0, this._postfft2BindGroup2);
832
- this._postfft2BindGroup2.setValue('N2', this._params.resolution * this._params.resolution);
833
887
  this._postfft2BindGroup2.setTexture('ifft4', ifftTextures[4], nearestRepeatSampler);
834
888
  this._postfft2BindGroup2.setTexture('ifft5', ifftTextures[5], nearestRepeatSampler);
835
- if (device.type === 'webgl') {
836
- this._postfft2BindGroup2.setValue('ifftTexSize', new Vector2(ifftTextures[0].width, ifftTextures[0].height));
837
- }
838
889
  FFTWaveGenerator._globals.quad.draw();
839
890
  }
840
891
  /** {@inheritDoc WaveGenerator.setupUniforms} */ setupUniforms(scope, uniformGroup) {
@@ -851,9 +902,65 @@ const THREAD_GROUP_SIZE = 16;
851
902
  scope.dx_hy_dz_dxdz2 = pb.tex2D().uniform(uniformGroup);
852
903
  scope.sx_sz_dxdx_dzdz2 = pb.tex2D().uniform(uniformGroup);
853
904
  }
854
- if (pb.shaderKind === 'fragment') {
855
- scope.foamParams = pb.vec2().uniform(uniformGroup);
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
+ });
856
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);
857
964
  }
858
965
  /** {@inheritDoc WaveGenerator.calcVertexPositionAndNormal} */ calcVertexPositionAndNormal(scope, inPos, outPos, outNormal) {
859
966
  const pb = scope.$builder;
@@ -903,13 +1010,31 @@ const THREAD_GROUP_SIZE = 16;
903
1010
  this.$l.sx = pb.add(this._sx_sz_dxdx_dzdz0.x, this._sx_sz_dxdx_dzdz1.x, this._sx_sz_dxdx_dzdz2.x);
904
1011
  this.$l.sz = pb.add(this._sx_sz_dxdx_dzdz0.y, this._sx_sz_dxdx_dzdz1.y, this._sx_sz_dxdx_dzdz2.y);
905
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));
906
- this.$l.slope = pb.vec2(pb.div(this.sx, pb.add(1.0, this.dxdx_dzdz.x)), pb.div(this.sz, pb.add(1.0, this.dxdx_dzdz.y)));
907
- this.$l.normal = pb.normalize(pb.vec3(pb.neg(this.slope.x), 1.0, pb.neg(this.slope.y)));
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
1016
+ //
1017
+ // N ~ ( -sx * F, J, -sz * A )
1018
+ //
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.
1022
+ let dxdzSamples;
1023
+ if (that._useComputeShader) {
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);
1025
+ } else {
1026
+ dxdzSamples = pb.vec3(pb.textureSampleLevel(this.dx_hy_dz_dxdz0, this.uv0, 0).w, pb.textureSampleLevel(this.dx_hy_dz_dxdz1, this.uv1, 0).w, pb.textureSampleLevel(this.dx_hy_dz_dxdz2, this.uv2, 0).w);
1027
+ }
1028
+ this.$l.dxdz = pb.add(pb.mul(dxdzSamples.x, this.croppinesses.x), pb.mul(dxdzSamples.y, this.croppinesses.y), pb.mul(dxdzSamples.z, this.croppinesses.z));
1029
+ this.$l.jA = pb.add(1.0, this.dxdx_dzdz.x);
1030
+ this.$l.jF = pb.add(1.0, this.dxdx_dzdz.y);
1031
+ this.$l.jdet = pb.sub(pb.mul(this.jA, this.jF), pb.mul(this.dxdz, this.dxdz));
1032
+ this.$l.normal = pb.normalize(pb.vec3(pb.neg(pb.mul(this.sx, this.jF)), pb.abs(this.jdet), pb.neg(pb.mul(this.sz, this.jA))));
908
1033
  this.$return(this.normal);
909
1034
  });
910
1035
  return scope.calcFragmentNormal(xz);
911
1036
  }
912
- /** {@inheritDoc WaveGenerator.calcFragmentNormalAndFoam} */ calcFragmentNormalAndFoam(scope, xz) {
1037
+ /** {@inheritDoc WaveGenerator.calcFragmentNormalAndFoam} */ calcFragmentNormalAndFoam(scope, xz, _vertexNormal, _foamSample, xzGrad) {
913
1038
  const pb = scope.$builder;
914
1039
  const that = this;
915
1040
  pb.func('jacobian', [
@@ -927,52 +1052,55 @@ const THREAD_GROUP_SIZE = 16;
927
1052
  ], function() {
928
1053
  this.$return(pb.sub(pb.mul(this.jacobian.x, this.jacobian.w), pb.mul(this.jacobian.y, this.jacobian.z)));
929
1054
  });
930
- pb.func('calcNormalAndFoam', [
1055
+ const params = xzGrad ? [
1056
+ pb.vec2('xz'),
1057
+ pb.vec4('xzGrad')
1058
+ ] : [
931
1059
  pb.vec2('xz')
932
- ], function() {
1060
+ ];
1061
+ const funcName = xzGrad ? 'calcNormalAndFoamF' : 'calcNormalAndFoam';
1062
+ pb.func(funcName, params, function() {
933
1063
  this.$l.uv0 = pb.div(this.xz, this.sizes.x);
934
1064
  this.$l.uv1 = pb.div(this.xz, this.sizes.y);
935
1065
  this.$l.uv2 = pb.div(this.xz, this.sizes.z);
936
- if (that._useComputeShader) {
937
- this.$l._sx_sz_dxdx_dzdz0 = pb.textureArraySampleLevel(this.dataTexture, this.uv0, 1, 0);
938
- this.$l._sx_sz_dxdx_dzdz1 = pb.textureArraySampleLevel(this.dataTexture, this.uv1, 3, 0);
939
- this.$l._sx_sz_dxdx_dzdz2 = pb.textureArraySampleLevel(this.dataTexture, this.uv2, 5, 0);
940
- } else {
941
- this.$l._sx_sz_dxdx_dzdz0 = pb.textureSampleLevel(this.sx_sz_dxdx_dzdz0, this.uv0, 0);
942
- this.$l._sx_sz_dxdx_dzdz1 = pb.textureSampleLevel(this.sx_sz_dxdx_dzdz1, this.uv1, 0);
943
- this.$l._sx_sz_dxdx_dzdz2 = pb.textureSampleLevel(this.sx_sz_dxdx_dzdz2, this.uv2, 0);
944
- }
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');
945
1081
  this.$l.sx = pb.add(this._sx_sz_dxdx_dzdz0.x, this._sx_sz_dxdx_dzdz1.x, this._sx_sz_dxdx_dzdz2.x);
946
1082
  this.$l.sz = pb.add(this._sx_sz_dxdx_dzdz0.y, this._sx_sz_dxdx_dzdz1.y, this._sx_sz_dxdx_dzdz2.y);
947
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));
948
- this.$l.slope = pb.vec2(pb.div(this.sx, pb.add(1.0, this.dxdx_dzdz.x)), pb.div(this.sz, pb.add(1.0, this.dxdx_dzdz.y)));
949
- this.$l.normal = pb.normalize(pb.vec3(pb.neg(this.slope.x), 1.0, pb.neg(this.slope.y)));
950
- // foam
951
- this.$l.dxdx_dzdz0 = this._sx_sz_dxdx_dzdz0.zw;
952
- this.$l.dxdx_dzdz1 = this._sx_sz_dxdx_dzdz1.zw;
953
- this.$l.dxdx_dzdz2 = this._sx_sz_dxdx_dzdz2.zw;
954
- if (that._useComputeShader) {
955
- this.$l.dxdz0 = pb.textureArraySampleLevel(this.dataTexture, this.uv0, 0, 0).w;
956
- this.$l.dxdz1 = pb.textureArraySampleLevel(this.dataTexture, this.uv1, 2, 0).w;
957
- this.$l.dxdz2 = pb.textureArraySampleLevel(this.dataTexture, this.uv2, 4, 0).w;
958
- } else {
959
- this.$l.dxdz0 = pb.textureSampleLevel(this.dx_hy_dz_dxdz0, this.uv0, 0).w;
960
- this.$l.dxdz1 = pb.textureSampleLevel(this.dx_hy_dz_dxdz1, this.uv1, 0).w;
961
- this.$l.dxdz2 = pb.textureSampleLevel(this.dx_hy_dz_dxdz2, this.uv2, 0).w;
962
- }
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;
963
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));
964
- this.$l.val = this.det(this.jacobian(this.dxdx_dzdz.x, this.dxdz, this.dxdx_dzdz.y));
1088
+ this.$l.jacobian4 = this.jacobian(this.dxdx_dzdz.x, this.dxdz, this.dxdx_dzdz.y);
1089
+ this.$l.val = this.det(this.jacobian4);
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.
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))));
965
1093
  this.$l.foam = pb.abs(pb.pow(pb.neg(pb.min(0, pb.sub(this.val, this.foamParams.x))), this.foamParams.y));
966
1094
  this.$return(pb.vec4(this.normal, this.foam));
967
1095
  });
968
- return scope.calcNormalAndFoam(xz);
1096
+ return xzGrad ? scope[funcName](xz, xzGrad) : scope[funcName](xz);
969
1097
  }
970
1098
  /** {@inheritDoc WaveGenerator.isOk} */ isOk() {
971
1099
  return this._renderMode !== RENDER_NONE;
972
1100
  }
973
1101
  /** {@inheritDoc WaveGenerator.applyWaterBindGroup} */ applyWaterBindGroup(bindGroup) {
974
1102
  const instanceData = this.getInstanceData();
975
- const linearRepeatSampler = fetchSampler('repeat_linear_nomip');
1103
+ const linearRepeatSampler = FFTWaveGenerator.getSlopeSampler();
976
1104
  if (this._useComputeShader) {
977
1105
  bindGroup.setTexture('dataTexture', instanceData.dataTextures, linearRepeatSampler);
978
1106
  } else {
@@ -987,6 +1115,10 @@ const THREAD_GROUP_SIZE = 16;
987
1115
  bindGroup.setValue('foamParams', this._params.foamParams);
988
1116
  bindGroup.setValue('sizes', this._sizes);
989
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);
990
1122
  }
991
1123
  /** {@inheritDoc WaveGenerator.calcClipmapTileAABB} */ calcClipmapTileAABB(minX, maxX, minZ, maxZ, y, outAABB) {
992
1124
  const disturb = Math.max(Math.abs(this.wind.x), Math.abs(this.wind.y), 2);