@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
@@ -0,0 +1,735 @@
1
+ import { Vector3, Vector4, DWeakRef, DRef, Vector2 } from '@zephyr3d/base';
2
+ import { ShaderHelper } from '../../material/shader/helper.js';
3
+ import '../../material/lambert.js';
4
+ import '../../material/blinn.js';
5
+ import '../../material/unlit.js';
6
+ import { applyMaterialMixins, MeshMaterial } from '../../material/meshmaterial.js';
7
+ import '../../material/particle.js';
8
+ import '../../material/subsurfaceprofile.js';
9
+ import '../../material/sssprofile.js';
10
+ import '../../material/sss.js';
11
+ import '../../material/eye.js';
12
+ import '@zephyr3d/device';
13
+ import { RENDER_PASS_TYPE_SHADOWMAP, RENDER_PASS_TYPE_LIGHT } from '../../values.js';
14
+ import '../../material/hair.js';
15
+ import '../../material/hairstrand.js';
16
+ import '../../material/grassmaterial.js';
17
+ import '../../material/terrain-cm.js';
18
+ import '../../material/pbrmr.js';
19
+ import '../../material/pbrsg.js';
20
+ import '../../material/mtoon.js';
21
+ import '../../material/pbrblueprint.js';
22
+ import '../../material/sprite.js';
23
+ import '../../material/sprite_std.js';
24
+ import '../../utility/blueprint/material/texture.js';
25
+ import { mixinPBRMetallicRoughness } from '../../material/mixins/lightmodel/pbrmetallicroughness.js';
26
+ import { grassBladeLodDistance, GRASS_BLADE_LOD_BAND } from './grass_gpu.js';
27
+ import { fetchSampler } from '../../utility/misc.js';
28
+
29
+ /**
30
+ * Vertex pairs across a blade at the high and the low detail level, each closed by one tip
31
+ * vertex: 15 and 7 vertices, as in "Procedural Grass in Ghost of Tsushima" (Wohllaib, GDC 2021)
32
+ */ const BLADE_HIGH_PAIRS = 7;
33
+ const BLADE_LOW_PAIRS = 3;
34
+ /**
35
+ * First vertex index of the low detail level. The vertex index tells the vertex shader which
36
+ * level it draws, so both draws share one program and one set of uniforms.
37
+ */ const BLADE_LOW_VERTEX_BASE = 16;
38
+ /** Number of vec4 per blade instance, see GrassGpuPlacement */ const BLADE_INSTANCE_VEC4 = 4;
39
+ /**
40
+ * Index counts of the high and the low detail level, which follow each other in the index buffer
41
+ * @internal
42
+ */ const BLADE_LOD_INDEX_COUNTS = [
43
+ BLADE_HIGH_PAIRS,
44
+ BLADE_LOW_PAIRS
45
+ ].map((pairs)=>(pairs - 1) * 6 + 3);
46
+ /**
47
+ * Triangle lists of a blade at the high then the low detail level: quads between consecutive
48
+ * vertex pairs, closed by the tip. Vertex base + 2k is the left side of pair k, base + 2k + 1 the
49
+ * right side, base + 2 * pairs the tip.
50
+ * @internal
51
+ */ function createBladeIndices() {
52
+ const indices = [];
53
+ const level = (base, pairs)=>{
54
+ for(let k = 0; k < pairs - 1; k++){
55
+ const a = base + 2 * k;
56
+ indices.push(a, a + 1, a + 3, a, a + 3, a + 2);
57
+ }
58
+ const last = base + 2 * (pairs - 1);
59
+ indices.push(last, last + 1, base + 2 * pairs);
60
+ };
61
+ level(0, BLADE_HIGH_PAIRS);
62
+ level(BLADE_LOW_VERTEX_BASE, BLADE_LOW_PAIRS);
63
+ return new Uint16Array(indices);
64
+ }
65
+ /**
66
+ * Terrain grass material for procedural blades.
67
+ *
68
+ * Each blade is a cubic Bezier curve built in the vertex shader from the vertex index and the
69
+ * blade's instance data, following "Procedural Grass in Ghost of Tsushima" (Wohllaib, GDC 2021):
70
+ * the tip is placed from the tilt and the facing, the middle control points are pushed away from
71
+ * the base-tip line by the bend, and the vertex steps sideways by the tapered width. The normal is
72
+ * the cross product of the curve derivative and the width direction.
73
+ *
74
+ * Three tricks from the talk make the blades read better:
75
+ * - rounded normals: the normal tilts outward across the blade's width, so a flat blade shades as
76
+ * if it were curved;
77
+ * - view-space thickening: a blade seen edge-on spreads its vertices sideways to the view, so it
78
+ * does not thin out to nothing;
79
+ * - distant normals: farther away the normal blends toward a normal shared by the whole clump and
80
+ * the surface gets rougher, which keeps distant fields from glittering. The talk does not say
81
+ * what that normal is; here it is the terrain normal (as in the cainrademan/Unity-Grass
82
+ * reimplementation) leaned toward the clump's facing by its tilt, so a distant field shades
83
+ * like a canopy lit from above instead of like blades turned away from a low sun.
84
+ *
85
+ * Color follows the talk too: a gradient along the blade whose column is picked by the blade's
86
+ * clump (a color texture, or root and tip colors with a per-clump brightness), and an ambient
87
+ * occlusion that darkens toward the root, where the other blades hide the sky.
88
+ *
89
+ * Two detail levels (see GrassGpuPlacement): near the switch distance, the three blades in four
90
+ * that give way shrink away while the fourth widens to four times its width - Outerra's
91
+ * procedural grass (outerra.blogspot.com, 2012) doubles the width for each halving of the blades
92
+ * to keep the ground as covered, and a quarter of the blades is two halvings - and morphs toward
93
+ * its low detail shape - the
94
+ * talk blends the high detail vertices toward the low detail shape; each vertex here moves onto
95
+ * the low detail outline the way CDLOD (Strugar, 2009) morphs terrain vertices onto the coarser
96
+ * grid - so the switch does not pop.
97
+ *
98
+ * Instance data is written by the GPU placement pass (GrassGpuPlacement), four vec4 per blade:
99
+ * - (base position xyz, 1 for a blade that gives way to the low detail level; +2 when flagged as
100
+ * occluded)
101
+ * - (facing angle, previous facing angle, wind push, previous wind push); the placement pass
102
+ * samples the scene wind for this frame and the last one and turns the facing downwind
103
+ * - (clump facing angle, clump color, packed terrain normal, per-blade hash)
104
+ * - (height, width, tilt, bend)
105
+ *
106
+ * @internal
107
+ */ class ClipmapBladeGrassMaterial extends applyMaterialMixins(MeshMaterial, mixinPBRMetallicRoughness) {
108
+ /** @internal */ _terrain;
109
+ /** @internal */ _instances;
110
+ /** @internal */ _colorMap;
111
+ /** (taper, tip detail, clump color variation, root occlusion) @internal */ _shape;
112
+ /** (roundness, view thickening, far normal start, far normal end) @internal */ _look;
113
+ /** (far roughness, unused...) @internal */ _look2;
114
+ /** (wind lean, sway amplitude, sway speed, unused) @internal */ _wind;
115
+ /** (wind clock, previous wind clock) @internal */ _windTime;
116
+ /** @internal */ _rootColor;
117
+ /** @internal */ _tipColor;
118
+ /** Light let through from behind at the tip, see transmissionColor @internal */ _transmissionColor;
119
+ /** @internal */ _distanceFade;
120
+ /** (low detail distance, first instance of the low detail list, unused, unused) @internal */ _lod;
121
+ /** @internal */ _lodDistance;
122
+ /** @internal */ _prevCameraPos;
123
+ /**
124
+ * Position of the camera the blades were placed for. A shadow map pass renders from the
125
+ * light, but the blades must take the shape they have in that camera's view to cast the
126
+ * shadows of the blades seen. @internal
127
+ */ _viewCameraPos;
128
+ /** @internal */ _drawDistance;
129
+ /** @internal */ _farDensity;
130
+ /**
131
+ * (world size of a pixel at distance 1, 1 for a perspective camera, minimum screen width in
132
+ * pixels, unused), see minScreenWidth @internal
133
+ */ _pixelSize;
134
+ /** @internal */ static _tmpPos = new Vector3();
135
+ /** @internal */ static FEATURE_OCCLUSION_DEBUG = this.defineFeature();
136
+ /** @internal */ static FEATURE_COLOR_MAP = this.defineFeature();
137
+ constructor(terrain){
138
+ super();
139
+ this.metallic = 0;
140
+ this.roughness = 0.6;
141
+ // Both sides are lit: the fragment shader turns the normal toward the viewer itself, since the
142
+ // generic flip would also turn the rounded normals inward on the back face
143
+ this.doubleSidedLighting = false;
144
+ this.specularFactor = new Vector4(1, 1, 1, 0.3);
145
+ this._terrain = new DWeakRef(terrain);
146
+ this._instances = new DRef();
147
+ this._colorMap = new DRef();
148
+ this._shape = new Vector4(0.7, 1.5, 0.6, 0.5);
149
+ this._look = new Vector4(0.5, 0.5, 15, 60);
150
+ this._look2 = new Vector4(0.9, 0, 0, 0);
151
+ this._wind = new Vector4(0.5, 0.15, 2.5, 0);
152
+ this._windTime = new Vector2(0, 0);
153
+ this._rootColor = new Vector4(0.06, 0.12, 0.02, 1);
154
+ this._tipColor = new Vector4(0.35, 0.45, 0.12, 1);
155
+ this._transmissionColor = new Vector4(0.45, 0.55, 0.12, 1);
156
+ this._distanceFade = new Vector2(0, 0);
157
+ this._lod = new Vector4(0, 0, 0, 0);
158
+ this._lodDistance = 0;
159
+ this._prevCameraPos = new Vector4();
160
+ this._viewCameraPos = new Vector4();
161
+ this._drawDistance = 0;
162
+ this._farDensity = 1;
163
+ this._pixelSize = new Vector4(0, 1, 1, 0);
164
+ this.useFeature(ClipmapBladeGrassMaterial.FEATURE_OCCLUSION_DEBUG, false);
165
+ this.useFeature(ClipmapBladeGrassMaterial.FEATURE_COLOR_MAP, false);
166
+ }
167
+ clone() {
168
+ const other = new ClipmapBladeGrassMaterial(this._terrain.get());
169
+ other.copyFrom(this);
170
+ return other;
171
+ }
172
+ copyFrom(other) {
173
+ super.copyFrom(other);
174
+ this._shape.set(other._shape);
175
+ this._look.set(other._look);
176
+ this._look2.set(other._look2);
177
+ this._wind.set(other._wind);
178
+ this.colorMap = other.colorMap;
179
+ this._rootColor.set(other._rootColor);
180
+ this._tipColor.set(other._tipColor);
181
+ this._transmissionColor.set(other._transmissionColor);
182
+ this._distanceFade.set(other._distanceFade);
183
+ this._drawDistance = other._drawDistance;
184
+ this._farDensity = other._farDensity;
185
+ this._pixelSize.set(other._pixelSize);
186
+ this._lodDistance = other._lodDistance;
187
+ this.updateDistanceParams();
188
+ }
189
+ /**
190
+ * Sets the instance buffer written by the GPU placement pass
191
+ * @internal
192
+ */ setInstanceBuffer(buffer, lowListBase) {
193
+ // Bound uniforms are only re-applied after uniformChanged(), and the placement pass
194
+ // reallocates the buffer whenever its placement window grows
195
+ if (buffer !== this._instances.get() || lowListBase !== this._lod.y) {
196
+ this._instances.set(buffer);
197
+ this._lod.y = lowListBase;
198
+ this.uniformChanged();
199
+ }
200
+ }
201
+ /**
202
+ * Distance at which the blades switch to the low detail level; 0 keeps them all at high detail
203
+ * @internal
204
+ */ get lodDistance() {
205
+ return this._lodDistance;
206
+ }
207
+ set lodDistance(val) {
208
+ val = Math.max(0, val);
209
+ if (val !== this._lodDistance) {
210
+ this._lodDistance = val;
211
+ this.updateDistanceParams();
212
+ }
213
+ }
214
+ /**
215
+ * Updates the per-frame values before drawing for a camera: the camera position the blades are
216
+ * shaped for, and the previous one the motion vectors are computed against
217
+ * @internal
218
+ */ prepareDraw(camera, wind, renderHeight = 0) {
219
+ // The pixel size is that of the camera's own view: shadow map passes pass 0 and keep it, so the
220
+ // blades cast the shadows of the blades seen, like the camera position below
221
+ if (renderHeight > 0) {
222
+ const projection = camera.getProjectionMatrix();
223
+ // Row 1, column 1 is 1 / tan(fovY / 2) for a perspective projection and 2 / height for an
224
+ // orthographic one, so either way the world size of a pixel is 2 / (m11 * renderHeight), at
225
+ // distance 1 for a perspective camera
226
+ const size = 2 / (projection.m11 * renderHeight);
227
+ const perspective = projection.isPerspective() ? 1 : 0;
228
+ const ps = this._pixelSize;
229
+ if (ps.x !== size || ps.y !== perspective) {
230
+ ps.x = size;
231
+ ps.y = perspective;
232
+ this.uniformChanged();
233
+ }
234
+ }
235
+ const pos = camera.getWorldPosition(ClipmapBladeGrassMaterial._tmpPos);
236
+ const c = this._viewCameraPos;
237
+ if (c.x !== pos.x || c.y !== pos.y || c.z !== pos.z) {
238
+ c.setXYZW(pos.x, pos.y, pos.z, 0);
239
+ this.uniformChanged();
240
+ }
241
+ const windParams = wind?.shaderParams;
242
+ const windTime = windParams ? windParams[13] : 0;
243
+ const prevWindTime = windParams ? windParams[16 + 13] : 0;
244
+ if (this._windTime.x !== windTime || this._windTime.y !== prevWindTime) {
245
+ this._windTime.setXY(windTime, prevWindTime);
246
+ this.uniformChanged();
247
+ }
248
+ const prev = camera.prevPosition ?? camera.getWorldPosition(ClipmapBladeGrassMaterial._tmpPos);
249
+ const p = this._prevCameraPos;
250
+ if (p.x !== prev.x || p.y !== prev.y || p.z !== prev.z) {
251
+ p.setXYZW(prev.x, prev.y, prev.z, 0);
252
+ this.uniformChanged();
253
+ }
254
+ }
255
+ /**
256
+ * Minimum width of a blade on screen, in pixels: farther blades are widened to it so they stay
257
+ * at least this wide instead of thinning below a pixel and flickering.
258
+ */ get minScreenWidth() {
259
+ return this._pixelSize.z;
260
+ }
261
+ set minScreenWidth(val) {
262
+ val = Math.min(4, Math.max(0, val));
263
+ if (val !== this._pixelSize.z) {
264
+ this._pixelSize.z = val;
265
+ this.uniformChanged();
266
+ }
267
+ }
268
+ /** How much the blade narrows toward the tip, 0 keeps it the same width up to the tip vertex */ get taper() {
269
+ return this._shape.x;
270
+ }
271
+ set taper(val) {
272
+ val = Math.min(1, Math.max(0, val));
273
+ if (val !== this._shape.x) {
274
+ this._shape.x = val;
275
+ this.uniformChanged();
276
+ }
277
+ }
278
+ /** Moves the vertices toward the tip, where the blade curves most. 1 spaces them evenly. */ get tipDetail() {
279
+ return this._shape.y;
280
+ }
281
+ set tipDetail(val) {
282
+ val = Math.min(4, Math.max(1, val));
283
+ if (val !== this._shape.y) {
284
+ this._shape.y = val;
285
+ this.uniformChanged();
286
+ }
287
+ }
288
+ /** How much the brightness changes from clump to clump, 0 for none */ get clumpColorVariation() {
289
+ return this._shape.z;
290
+ }
291
+ set clumpColorVariation(val) {
292
+ val = Math.min(1, Math.max(0, val));
293
+ if (val !== this._shape.z) {
294
+ this._shape.z = val;
295
+ this.uniformChanged();
296
+ }
297
+ }
298
+ /** How much the ambient light darkens toward the root, 0 for none, 1 for black at the root */ get rootOcclusion() {
299
+ return this._shape.w;
300
+ }
301
+ set rootOcclusion(val) {
302
+ val = Math.min(1, Math.max(0, val));
303
+ if (val !== this._shape.w) {
304
+ this._shape.w = val;
305
+ this.uniformChanged();
306
+ }
307
+ }
308
+ /**
309
+ * Optional color texture: V from the root (0) to the tip (1), U picked per clump. Replaces the
310
+ * root and tip colors.
311
+ */ get colorMap() {
312
+ return this._colorMap.get();
313
+ }
314
+ set colorMap(val) {
315
+ if (val !== this._colorMap.get()) {
316
+ this._colorMap.set(val);
317
+ this.useFeature(ClipmapBladeGrassMaterial.FEATURE_COLOR_MAP, !!val);
318
+ this.uniformChanged();
319
+ }
320
+ }
321
+ /**
322
+ * How much the normals tilt outward across the blade, making flat blades shade as if curved.
323
+ * 0 shades them flat.
324
+ */ get roundness() {
325
+ return this._look.x;
326
+ }
327
+ set roundness(val) {
328
+ val = Math.min(2, Math.max(0, val));
329
+ if (val !== this._look.x) {
330
+ this._look.x = val;
331
+ this.uniformChanged();
332
+ }
333
+ }
334
+ /**
335
+ * How much a blade seen edge-on is widened toward the viewer, as a fraction of its width.
336
+ * Keeps fields looking full from low angles. 0 disables it.
337
+ */ get viewThickening() {
338
+ return this._look.y;
339
+ }
340
+ set viewThickening(val) {
341
+ val = Math.min(2, Math.max(0, val));
342
+ if (val !== this._look.y) {
343
+ this._look.y = val;
344
+ this.uniformChanged();
345
+ }
346
+ }
347
+ /** Distance at which the blade normals start blending toward their clump's shared normal */ get farNormalStart() {
348
+ return this._look.z;
349
+ }
350
+ set farNormalStart(val) {
351
+ val = Math.max(0, val);
352
+ if (val !== this._look.z) {
353
+ this._look.z = val;
354
+ this.uniformChanged();
355
+ }
356
+ }
357
+ /** Distance at which the blade normals are fully their clump's shared normal */ get farNormalEnd() {
358
+ return this._look.w;
359
+ }
360
+ set farNormalEnd(val) {
361
+ val = Math.max(0, val);
362
+ if (val !== this._look.w) {
363
+ this._look.w = val;
364
+ this.uniformChanged();
365
+ }
366
+ }
367
+ /** Roughness the blades reach at the far normal end distance, dulling distant highlights */ get farRoughness() {
368
+ return this._look2.x;
369
+ }
370
+ set farRoughness(val) {
371
+ val = Math.min(1, Math.max(0, val));
372
+ if (val !== this._look2.x) {
373
+ this._look2.x = val;
374
+ this.uniformChanged();
375
+ }
376
+ }
377
+ /**
378
+ * How far the wind lays the blades over toward lying flat, per unit of wind push. 0 leaves
379
+ * their lean alone.
380
+ */ get windLean() {
381
+ return this._wind.x;
382
+ }
383
+ set windLean(val) {
384
+ val = Math.min(4, Math.max(0, val));
385
+ if (val !== this._wind.x) {
386
+ this._wind.x = val;
387
+ this.uniformChanged();
388
+ }
389
+ }
390
+ /** How far the blade tips bob in the wind, as a fraction of the blade height per unit of push */ get swayAmplitude() {
391
+ return this._wind.y;
392
+ }
393
+ set swayAmplitude(val) {
394
+ val = Math.min(1, Math.max(0, val));
395
+ if (val !== this._wind.y) {
396
+ this._wind.y = val;
397
+ this.uniformChanged();
398
+ }
399
+ }
400
+ /** How fast the blades bob in the wind, in radians per second */ get swaySpeed() {
401
+ return this._wind.z;
402
+ }
403
+ set swaySpeed(val) {
404
+ val = Math.min(50, Math.max(0, val));
405
+ if (val !== this._wind.z) {
406
+ this._wind.z = val;
407
+ this.uniformChanged();
408
+ }
409
+ }
410
+ /** Color at the root of the blades */ get rootColor() {
411
+ return this._rootColor;
412
+ }
413
+ set rootColor(val) {
414
+ this._rootColor.set(val);
415
+ this.uniformChanged();
416
+ }
417
+ /** Color at the tip of the blades */ get tipColor() {
418
+ return this._tipColor;
419
+ }
420
+ set tipColor(val) {
421
+ this._tipColor.set(val);
422
+ this.uniformChanged();
423
+ }
424
+ /** Color of the light the blades let through from behind. */ get transmissionColor() {
425
+ return this._transmissionColor;
426
+ }
427
+ set transmissionColor(val) {
428
+ this._transmissionColor.set(val);
429
+ this.uniformChanged();
430
+ }
431
+ /** @internal */ setDrawDistance(distance) {
432
+ this._drawDistance = distance;
433
+ this.updateDistanceParams();
434
+ }
435
+ /**
436
+ * Kept for the interface shared with the card material: blades thin out by their detail levels
437
+ * instead
438
+ * @internal
439
+ */ setFarDensity(farDensity) {
440
+ this._farDensity = farDensity;
441
+ }
442
+ /** @internal */ updateDistanceParams() {
443
+ const distance = this._drawDistance;
444
+ this._distanceFade.setXY(distance > 0 ? distance * 0.75 : 0, distance > 0 ? distance : 0);
445
+ // The same switch distance as the placement pass
446
+ this._lod.x = grassBladeLodDistance(this._lodDistance, distance);
447
+ this.uniformChanged();
448
+ }
449
+ /** @internal */ get occlusionDebug() {
450
+ return !!this.featureUsed(ClipmapBladeGrassMaterial.FEATURE_OCCLUSION_DEBUG);
451
+ }
452
+ set occlusionDebug(val) {
453
+ this.useFeature(ClipmapBladeGrassMaterial.FEATURE_OCCLUSION_DEBUG, !!val);
454
+ }
455
+ isTransparentPass(_pass) {
456
+ return false;
457
+ }
458
+ supportLighting() {
459
+ return true;
460
+ }
461
+ supportInstancing() {
462
+ return false;
463
+ }
464
+ applyUniformValues(bindGroup, ctx, pass) {
465
+ super.applyUniformValues(bindGroup, ctx, pass);
466
+ bindGroup.setBuffer('zBladeInstances', this._instances.get());
467
+ bindGroup.setValue('zBladeShape', this._shape);
468
+ bindGroup.setValue('zBladeLook', this._look);
469
+ bindGroup.setValue('zBladeLook2', this._look2);
470
+ bindGroup.setValue('zBladeWind', this._wind);
471
+ bindGroup.setValue('zWindTime', this._windTime);
472
+ bindGroup.setValue('zDistanceFade', this._distanceFade);
473
+ bindGroup.setValue('zBladeLod', this._lod);
474
+ bindGroup.setValue('zPrevCameraPos', this._prevCameraPos);
475
+ bindGroup.setValue('zBladePixel', this._pixelSize);
476
+ if (ctx.renderPass.type === RENDER_PASS_TYPE_SHADOWMAP) {
477
+ bindGroup.setValue('zViewCameraPos', this._viewCameraPos);
478
+ }
479
+ if (this.needFragmentColor(ctx)) {
480
+ bindGroup.setValue('zRootColor', this._rootColor);
481
+ bindGroup.setValue('zTipColor', this._tipColor);
482
+ bindGroup.setValue('zBladeTransmission', this._transmissionColor);
483
+ bindGroup.setValue('zBladeRoundness', this._look.x);
484
+ if (this._colorMap.get()) {
485
+ bindGroup.setTexture('zColorMap', this._colorMap.get(), fetchSampler('clamp_linear'));
486
+ }
487
+ }
488
+ }
489
+ /**
490
+ * Emits the world position and flat normal of the current vertex of a blade as seen from a
491
+ * camera position, into `worldPos` and `flatNormal` suffixed by `suffix`. The camera position
492
+ * drives the detail level transition, the draw distance fade and the view-space thickening.
493
+ */ emitBladeVertex(scope, cameraPos, facingAngle, windPush, windTime, suffix) {
494
+ const pb = scope.$builder;
495
+ const v = (name)=>`${name}${suffix}`;
496
+ // Blade frame: facing on the ground plane (already turned downwind by the placement pass),
497
+ // width across it, tip leaning by the tilt, which the wind raises toward lying flat: the
498
+ // "general bias away from the wind" of the Ghost of Tsushima talks
499
+ scope.$l[v('facing')] = pb.vec3(pb.cos(facingAngle), 0, pb.sin(facingAngle));
500
+ scope.$l[v('widthDir')] = pb.vec3(pb.neg(scope[v('facing')].z), 0, scope[v('facing')].x);
501
+ scope.$l[v('tilt')] = pb.add(scope.inst3.z, pb.mul(pb.sub(1, scope.inst3.z), pb.clamp(pb.mul(windPush, scope.zBladeWind.x), 0, 0.95)));
502
+ scope.$l[v('tiltAngle')] = pb.mul(scope[v('tilt')], Math.PI * 0.5);
503
+ scope.$l[v('tipDir')] = pb.add(pb.mul(scope[v('facing')], pb.sin(scope[v('tiltAngle')])), pb.vec3(0, pb.cos(scope[v('tiltAngle')]), 0));
504
+ scope.$l[v('bendDir')] = pb.add(pb.mul(scope[v('facing')], pb.neg(pb.cos(scope[v('tiltAngle')]))), pb.vec3(0, pb.sin(scope[v('tiltAngle')]), 0));
505
+ // Detail level transition over the last band before the switch distance: 0 before it, 1 at and
506
+ // past it, which is where every blade of the low detail list is
507
+ scope.$l[v('bladeDist')] = pb.distance(cameraPos, scope.base);
508
+ scope.$l[v('lodFade')] = pb.smoothStep(pb.mul(scope.zBladeLod.x, 1 - GRASS_BLADE_LOD_BAND), scope.zBladeLod.x, scope[v('bladeDist')]);
509
+ // (width scale, overall scale): the blades that stay widen to four times their width, the others
510
+ // shrink away; everything shrinks into the ground over the last quarter of the draw distance
511
+ scope.$l[v('bladeScale')] = pb.vec2(pb.add(1, pb.mul(scope[v('lodFade')], 3)), pb.sub(1, pb.mul(scope.extra, scope[v('lodFade')])));
512
+ scope.$if(pb.greaterThan(scope.zDistanceFade.y, 0), function() {
513
+ this[v('bladeScale')] = pb.vec2(this[v('bladeScale')].x, pb.mul(this[v('bladeScale')].y, pb.sub(1, pb.smoothStep(this.zDistanceFade.x, this.zDistanceFade.y, this[v('bladeDist')]))));
514
+ });
515
+ const s = scope[v('bladeScale')];
516
+ scope.$l[v('h')] = pb.mul(scope.inst3.x, s.y);
517
+ scope.$l[v('widthScale')] = pb.mul(scope.inst3.y, s.x, s.y, 0.5);
518
+ // Cubic Bezier from the base: tip from tilt and facing, middle points pushed away from the
519
+ // base-tip line by the bend (up and back when the blade leans forward)
520
+ scope.$l[v('p3')] = pb.mul(scope[v('tipDir')], scope[v('h')]);
521
+ scope.$l[v('bendOffset')] = pb.mul(scope[v('bendDir')], pb.mul(scope.inst3.w, scope[v('h')]));
522
+ scope.$l[v('p1')] = pb.add(pb.mul(scope[v('p3')], 1 / 3), scope[v('bendOffset')]);
523
+ scope.$l[v('p2')] = pb.add(pb.mul(scope[v('p3')], 2 / 3), scope[v('bendOffset')]);
524
+ // Sway: a sine bob of the upper control points, whose phase comes from the blade's hash and
525
+ // the position along the blade (Ghost of Tsushima), scaled by the wind push. Applying it to
526
+ // the last two control points with weights 2/3 and 1 follows cainrademan/Unity-Grass.
527
+ scope.$l[v('swayPhase')] = pb.add(pb.mul(windTime, scope.zBladeWind.z), pb.mul(scope.inst2.w, Math.PI * 2));
528
+ scope.$l[v('swayAmount')] = pb.mul(scope.zBladeWind.y, scope[v('h')], windPush);
529
+ scope[v('p2')] = pb.add(scope[v('p2')], pb.mul(scope[v('bendDir')], pb.mul(scope[v('swayAmount')], 2 / 3, pb.sin(pb.add(scope[v('swayPhase')], Math.PI * 4 / 3)))));
530
+ scope[v('p3')] = pb.add(scope[v('p3')], pb.mul(scope[v('bendDir')], pb.mul(scope[v('swayAmount')], pb.sin(scope[v('swayPhase')]))));
531
+ // Point of the blade at curve parameter t on side `side` (-1, 1, 0 on the center line), into
532
+ // `${tag}Pos` and `${tag}Normal`
533
+ const point = (sc, t, side, tag)=>{
534
+ sc.$l[`${tag}T`] = t;
535
+ sc.$l[`${tag}Omt`] = pb.sub(1, sc[`${tag}T`]);
536
+ const tt = sc[`${tag}T`];
537
+ const omt = sc[`${tag}Omt`];
538
+ sc.$l[`${tag}Curve`] = pb.add(pb.mul(sc[v('p1')], pb.mul(3, omt, omt, tt)), pb.mul(sc[v('p2')], pb.mul(3, omt, tt, tt)), pb.mul(sc[v('p3')], pb.mul(tt, tt, tt)));
539
+ sc.$l[`${tag}Tangent`] = pb.add(pb.mul(sc[v('p1')], pb.mul(3, omt, pb.sub(omt, pb.mul(tt, 2)))), pb.mul(sc[v('p2')], pb.mul(3, tt, pb.sub(pb.mul(omt, 2), tt))), pb.mul(sc[v('p3')], pb.mul(3, tt, tt)));
540
+ sc.$l[`${tag}HalfWidth`] = pb.mul(sc[v('widthScale')], pb.mix(1, omt, sc.zBladeShape.x));
541
+ // View-space thickening: when the blade's normal is nearly orthogonal to the view vector the
542
+ // blade is seen edge-on, so its sides also step apart across the view. The response curve
543
+ // is the one of the cainrademan/Unity-Grass reimplementation.
544
+ sc.$l[`${tag}Centre`] = pb.add(sc.base, sc[`${tag}Curve`]);
545
+ sc.$l[`${tag}ToCamera`] = pb.normalize(pb.sub(cameraPos, sc[`${tag}Centre`]));
546
+ sc.$l[`${tag}Normal`] = pb.normalize(pb.cross(sc[v('widthDir')], sc[`${tag}Tangent`]));
547
+ sc.$l[`${tag}EdgeOn`] = pb.sub(1, pb.smoothStep(0, 0.3, pb.abs(pb.dot(sc[`${tag}Normal`], sc[`${tag}ToCamera`]))));
548
+ sc.$l[`${tag}Across`] = pb.cross(sc[`${tag}ToCamera`], pb.normalize(sc[`${tag}Tangent`]));
549
+ // Keep the sides on the same side as the blade's own width, so the blade never folds over
550
+ sc[`${tag}Across`] = pb.mul(sc[`${tag}Across`], pb.sub(pb.mul(pb.step(0, pb.dot(sc[`${tag}Across`], sc[v('widthDir')])), 2), 1));
551
+ sc.$l[`${tag}Pos`] = pb.add(sc[`${tag}Centre`], pb.mul(sc[v('widthDir')], pb.mul(side, sc[`${tag}HalfWidth`])), pb.mul(sc[`${tag}Across`], pb.mul(side, sc[`${tag}HalfWidth`], sc.zBladeLook.y, sc[`${tag}EdgeOn`])));
552
+ sc.$l[`${tag}AcrossLen`] = pb.length(sc[`${tag}Across`]);
553
+ sc.$l[`${tag}AcrossDir`] = pb.div(sc[`${tag}Across`], pb.max(sc[`${tag}AcrossLen`], 1e-4));
554
+ sc.$l[`${tag}SeenHalfWidth`] = pb.mul(sc[`${tag}HalfWidth`], pb.add(pb.abs(pb.dot(sc[v('widthDir')], sc[`${tag}AcrossDir`])), pb.mul(sc.zBladeLook.y, sc[`${tag}EdgeOn`], sc[`${tag}AcrossLen`])));
555
+ sc.$l[`${tag}MinHalfWidth`] = pb.mul(0.5, sc.zBladePixel.z, sc.zBladePixel.x, pb.mix(1, pb.distance(cameraPos, sc[`${tag}Centre`]), sc.zBladePixel.y), sc[v('bladeScale')].y);
556
+ sc[`${tag}Pos`] = pb.add(sc[`${tag}Pos`], pb.mul(sc[`${tag}AcrossDir`], pb.mul(side, pb.max(pb.sub(sc[`${tag}MinHalfWidth`], sc[`${tag}SeenHalfWidth`]), 0))));
557
+ };
558
+ point(scope, scope.t, scope.side, v('zv'));
559
+ scope.$l[v('worldPos')] = scope[`${v('zv')}Pos`];
560
+ scope.$l[v('flatNormal')] = scope[`${v('zv')}Normal`];
561
+ // Through the transition band the high detail vertices move onto the low detail outline: a
562
+ // vertex at `along` lands between the two low detail vertices around it, in proportion, as
563
+ // CDLOD (Strugar, 2009) morphs terrain vertices onto the coarser grid. The tip vertex is on
564
+ // both outlines already.
565
+ //
566
+ // Only this frame's vertex is morphed; last frame's takes the same morph offset. Morphing it
567
+ // again from last frame's inputs left the motion vectors NaN across the band with TAA on (the
568
+ // same code runs clean for this frame, the cause was not pinned down), and the offset changes
569
+ // little in a frame: the morph spans the last quarter of the switch distance.
570
+ if (suffix) {
571
+ scope[v('worldPos')] = pb.add(scope[v('worldPos')], scope.zMorphOffset);
572
+ return;
573
+ }
574
+ scope.$l.zMorphOffset = pb.vec3(0);
575
+ scope.$if(pb.and(pb.not(scope.isLow), pb.greaterThan(scope[v('lodFade')], 0)), function() {
576
+ this.$l[v('ma')] = pb.mul(this.along, BLADE_LOW_PAIRS);
577
+ this.$l[v('mj')] = pb.min(pb.floor(this[v('ma')]), BLADE_LOW_PAIRS - 1);
578
+ this.$l[v('mf')] = pb.sub(this[v('ma')], this[v('mj')]);
579
+ // Past the last low detail pair comes the tip, on the center line
580
+ this.$l[v('mSide')] = pb.mul(this.side, pb.step(this[v('mj')], BLADE_LOW_PAIRS - 2));
581
+ point(this, this.zAlongToT(pb.div(this[v('mj')], BLADE_LOW_PAIRS)), this.side, v('zm0'));
582
+ point(this, this.zAlongToT(pb.div(pb.add(this[v('mj')], 1), BLADE_LOW_PAIRS)), this[v('mSide')], v('zm1'));
583
+ this.zMorphOffset = pb.mul(pb.sub(pb.mix(this[`${v('zm0')}Pos`], this[`${v('zm1')}Pos`], this[v('mf')]), this[v('worldPos')]), this[v('lodFade')]);
584
+ this[v('worldPos')] = pb.add(this[v('worldPos')], this.zMorphOffset);
585
+ });
586
+ }
587
+ vertexShader(scope) {
588
+ super.vertexShader(scope);
589
+ const pb = scope.$builder;
590
+ scope.zBladeInstances = pb.vec4[0]().storageBufferReadonly(2);
591
+ scope.zBladeShape = pb.vec4().uniform(2);
592
+ scope.zBladeLook = pb.vec4().uniform(2);
593
+ scope.zBladeLook2 = pb.vec4().uniform(2);
594
+ scope.zDistanceFade = pb.vec2().uniform(2);
595
+ // (low detail distance, first instance of the low detail list, unused, unused)
596
+ scope.zBladeLod = pb.vec4().uniform(2);
597
+ scope.zPrevCameraPos = pb.vec4().uniform(2);
598
+ // (pixel size at distance 1, perspective flag, minimum screen width in pixels, unused)
599
+ scope.zBladePixel = pb.vec4().uniform(2);
600
+ // (wind lean, sway amplitude, sway speed, unused)
601
+ scope.zBladeWind = pb.vec4().uniform(2);
602
+ // (wind clock, previous wind clock)
603
+ scope.zWindTime = pb.vec2().uniform(2);
604
+ // Shadow map passes render from the light: the blades are shaped for the camera they were
605
+ // placed for instead, see _viewCameraPos
606
+ const shadowPass = this.drawContext.renderPass.type === RENDER_PASS_TYPE_SHADOWMAP;
607
+ if (shadowPass) {
608
+ scope.zViewCameraPos = pb.vec4().uniform(2);
609
+ }
610
+ scope.$l.zBladeViewPos = shadowPass ? scope.zViewCameraPos.xyz : ShaderHelper.getCameraPosition(scope);
611
+ // Position along the blade (0 at the root, 1 at the tip) to curve parameter: the vertices are
612
+ // spread toward the tip by the tip detail exponent
613
+ pb.func('zAlongToT', [
614
+ pb.float('a')
615
+ ], function() {
616
+ this.$return(pb.sub(1, pb.pow(pb.sub(1, this.a), this.zBladeShape.y)));
617
+ });
618
+ // The vertex index tells the detail level: the low detail draw's indices start at
619
+ // BLADE_LOW_VERTEX_BASE, and its instances at the low detail list
620
+ scope.$l.isLow = pb.greaterThanEqual(pb.uint(scope.$builtins.vertexIndex), pb.uint(BLADE_LOW_VERTEX_BASE));
621
+ scope.$l.vid = pb.sub(pb.uint(scope.$builtins.vertexIndex), scope.$choice(scope.isLow, pb.uint(BLADE_LOW_VERTEX_BASE), pb.uint(0)));
622
+ scope.$l.pairs = scope.$choice(scope.isLow, pb.float(BLADE_LOW_PAIRS), pb.float(BLADE_HIGH_PAIRS));
623
+ scope.$l.first = pb.mul(pb.add(pb.uint(scope.$builtins.instanceIndex), scope.$choice(scope.isLow, pb.uint(scope.zBladeLod.y), pb.uint(0))), BLADE_INSTANCE_VEC4);
624
+ scope.$l.inst0 = scope.zBladeInstances.at(scope.first);
625
+ scope.$l.inst1 = scope.zBladeInstances.at(pb.add(scope.first, 1));
626
+ scope.$l.inst2 = scope.zBladeInstances.at(pb.add(scope.first, 2));
627
+ scope.$l.inst3 = scope.zBladeInstances.at(pb.add(scope.first, 3));
628
+ scope.$l.base = scope.inst0.xyz;
629
+ // The placement pass adds 2 to the hash of blades it flags as occluded
630
+ scope.$l.occluded = pb.step(1.5, scope.inst0.w);
631
+ if (this.occlusionDebug) {
632
+ scope.$outputs.zOccludedFlag = scope.occluded;
633
+ }
634
+ // 1 for a blade that gives way to the low detail level
635
+ scope.$l.extra = pb.sub(scope.inst0.w, pb.mul(scope.occluded, 2));
636
+ // Where the vertex lies along the blade and on which side; the tip vertex sits on the center
637
+ // line
638
+ scope.$l.isTip = pb.greaterThanEqual(scope.vid, pb.uint(pb.mul(scope.pairs, 2)));
639
+ scope.$l.along = pb.div(pb.float(pb.sar(scope.vid, 1)), scope.pairs);
640
+ scope.along = pb.mix(scope.along, 1, pb.float(scope.isTip));
641
+ scope.$l.t = scope.zAlongToT(scope.along);
642
+ scope.$l.side = pb.mul(pb.sub(pb.mul(pb.float(pb.compAnd(scope.vid, pb.uint(1))), 2), 1), pb.sub(1, pb.float(scope.isTip)));
643
+ // Instance: (facing, previous facing, wind push, previous wind push)
644
+ this.emitBladeVertex(scope, scope.zBladeViewPos, scope.inst1.x, scope.inst1.z, scope.zWindTime.x, '');
645
+ scope.$outputs.worldPos = scope.worldPos;
646
+ scope.$outputs.worldNorm = scope.flatNormal;
647
+ // For the rounded normals: which way is across the blade, and how far across this vertex is
648
+ scope.$outputs.zBladeWidthDir = scope.widthDir;
649
+ scope.$outputs.zBladeSide = scope.side;
650
+ // Normal shared by the clump: the terrain normal leaned toward the clump's facing by the tilt
651
+ scope.$l.clumpFacing = pb.vec3(pb.cos(scope.inst2.x), 0, pb.sin(scope.inst2.x));
652
+ scope.$l.packedX = pb.floor(pb.div(scope.inst2.z, 4096));
653
+ scope.$l.terrainXZ = pb.sub(pb.mul(pb.div(pb.vec2(scope.packedX, pb.sub(scope.inst2.z, pb.mul(scope.packedX, 4096))), 4095), 2), pb.vec2(1));
654
+ scope.$l.terrainNormal = pb.vec3(scope.terrainXZ.x, pb.sqrt(pb.max(0, pb.sub(1, pb.dot(scope.terrainXZ, scope.terrainXZ)))), scope.terrainXZ.y);
655
+ scope.$outputs.zBladeClumpNormal = pb.normalize(pb.add(scope.terrainNormal, pb.mul(scope.clumpFacing, pb.mul(pb.sin(scope.tiltAngle), 0.5))));
656
+ // (blend toward the clump normal and the far roughness, far roughness)
657
+ scope.$outputs.zBladeFar = pb.vec2(pb.smoothStep(scope.zBladeLook.z, pb.max(scope.zBladeLook.w, pb.add(scope.zBladeLook.z, 1e-3)), pb.distance(scope.zBladeViewPos, scope.worldPos)), scope.zBladeLook2.x);
658
+ scope.$outputs.zBladeT = scope.t;
659
+ scope.$outputs.zBladeClumpColor = scope.inst2.y;
660
+ // Per-clump brightness, and ambient occlusion darkening toward the root
661
+ scope.$outputs.zBladeBrightness = pb.max(0, pb.add(1, pb.mul(scope.zBladeShape.z, pb.sub(pb.mul(scope.inst2.y, 2), 1))));
662
+ scope.$outputs.zBladeAO = pb.sub(1, pb.mul(scope.zBladeShape.w, pb.sub(1, scope.t)));
663
+ ShaderHelper.setClipSpacePosition(scope, pb.mul(ShaderHelper.getViewProjectionMatrix(scope), pb.vec4(scope.worldPos, 1)));
664
+ if (ShaderHelper.getPrevUnjitteredViewProjectionMatrix(scope)) {
665
+ // Where this vertex was last frame, for the motion vectors: the blade is rebuilt from last
666
+ // frame's wind, wind clock and camera (for the density LOD fade and the thickening)
667
+ this.emitBladeVertex(scope, scope.zPrevCameraPos.xyz, scope.inst1.y, scope.inst1.w, scope.zWindTime.y, 'Prev');
668
+ ShaderHelper.resolveMotionVector(scope, scope.worldPos, scope.worldPosPrev);
669
+ }
670
+ }
671
+ fragmentShader(scope) {
672
+ super.fragmentShader(scope);
673
+ const pb = scope.$builder;
674
+ if (this.needFragmentColor()) {
675
+ scope.zRootColor = pb.vec4().uniform(2);
676
+ scope.zTipColor = pb.vec4().uniform(2);
677
+ scope.zBladeTransmission = pb.vec4().uniform(2);
678
+ scope.zBladeRoundness = pb.float().uniform(2);
679
+ if (this.featureUsed(ClipmapBladeGrassMaterial.FEATURE_COLOR_MAP)) {
680
+ scope.zColorMap = pb.tex2D().uniform(2);
681
+ scope.$l.albedo = pb.textureSampleLevel(scope.zColorMap, pb.vec2(scope.$inputs.zBladeClumpColor, scope.$inputs.zBladeT), 0);
682
+ } else {
683
+ scope.$l.albedo = pb.mix(scope.zRootColor, scope.zTipColor, scope.$inputs.zBladeT);
684
+ }
685
+ // Per-clump brightness: splashes of variation across the field
686
+ scope.albedo = pb.vec4(pb.mul(scope.albedo.rgb, scope.$inputs.zBladeBrightness), 1);
687
+ if (this.occlusionDebug) {
688
+ scope.albedo = pb.vec4(pb.mix(scope.albedo.rgb, pb.vec3(1, 0, 0), scope.$inputs.zOccludedFlag), scope.albedo.a);
689
+ }
690
+ scope.$l.litColor = pb.vec3(0);
691
+ if (this.drawContext.renderPass.type === RENDER_PASS_TYPE_LIGHT) {
692
+ scope.$l.viewVec = this.calculateViewVector(scope, scope.$inputs.worldPos);
693
+ // Both faces are lit from the side facing the viewer, then the normal tilts outward across
694
+ // the blade (rounded normals) and, far away, blends toward the clump's shared normal
695
+ scope.$l.towardViewer = pb.sub(pb.mul(pb.step(0, pb.dot(scope.$inputs.worldNorm, scope.viewVec)), 2), 1);
696
+ scope.$l.bladeNormal = pb.normalize(pb.add(pb.mul(pb.normalize(scope.$inputs.worldNorm), scope.towardViewer), pb.mul(scope.$inputs.zBladeWidthDir, pb.mul(scope.$inputs.zBladeSide, scope.zBladeRoundness))));
697
+ scope.bladeNormal = pb.normalize(pb.mix(scope.bladeNormal, pb.normalize(scope.$inputs.zBladeClumpNormal), scope.$inputs.zBladeFar.x));
698
+ scope.$l.normalInfo = this.calculateNormalAndTBN(scope, scope.$inputs.worldPos, scope.bladeNormal);
699
+ scope.$l.litColor = this.PBRLight(scope, scope.$inputs.worldPos, scope.normalInfo.normal, scope.viewVec, scope.albedo, scope.normalInfo.TBN);
700
+ }
701
+ this.outputFragmentColor(scope, scope.$inputs.worldPos, pb.vec4(scope.litColor, 1));
702
+ } else {
703
+ this.outputFragmentColor(scope, scope.$inputs.worldPos, null);
704
+ }
705
+ }
706
+ /** Distant blades get rougher, see farRoughness */ calculateRoughness(scope, albedo, normal) {
707
+ const pb = scope.$builder;
708
+ const roughness = super.calculateRoughness(scope, albedo, normal);
709
+ return pb.mix(roughness, pb.max(roughness, scope.$inputs.zBladeFar.y), scope.$inputs.zBladeFar.x);
710
+ }
711
+ /**
712
+ * Light through the blade from behind, see MeshMaterial.getSubsurfaceColor. Ghost of Tsushima's
713
+ * blades are thick and let little light through at the root and more toward the tip; here it
714
+ * grows linearly along the blade up to the transmission color.
715
+ */ getSubsurfaceColor(scope) {
716
+ const pb = scope.$builder;
717
+ return pb.mul(scope.zBladeTransmission.rgb, scope.$inputs.zBladeT);
718
+ }
719
+ /** Ambient occlusion darkening toward the root, see MeshMaterial.getAmbientOcclusionFactor */ getAmbientOcclusionFactor(scope) {
720
+ return scope.$inputs.zBladeAO;
721
+ }
722
+ updateRenderStates(pass, stateSet, ctx) {
723
+ super.updateRenderStates(pass, stateSet, ctx);
724
+ stateSet.useRasterizerState().setCullMode('none');
725
+ }
726
+ onDispose() {
727
+ super.onDispose();
728
+ this._instances.dispose();
729
+ this._colorMap.dispose();
730
+ this._terrain.dispose();
731
+ }
732
+ }
733
+
734
+ export { BLADE_INSTANCE_VEC4, BLADE_LOD_INDEX_COUNTS, ClipmapBladeGrassMaterial, createBladeIndices };
735
+ //# sourceMappingURL=bladegrassmaterial.js.map