@woosh/meep-engine 3.67.0 → 3.68.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 (311) hide show
  1. package/package.json +1 -1
  2. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  3. package/src/engine/graphics3/GraphicsEngine.js +4 -9
  4. package/src/engine/graphics3/load_cube_environment.js +3 -3
  5. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  6. package/src/shade/playground/probe_clipmap/index.html +43 -0
  7. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  8. package/src/shade/playground/probe_clipmap/main.js +29 -0
  9. package/src/shade/renderer/Renderer.d.ts +7 -0
  10. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  11. package/src/shade/renderer/Renderer.js +213 -15
  12. package/src/shade/renderer/ShadeIndirectLightingMode.d.ts +1 -0
  13. package/src/shade/renderer/ShadeIndirectLightingMode.js +9 -0
  14. package/src/shade/renderer/atmosphere/ATMOSPHERE_PARAMETERS_STRUCT.d.ts +22 -0
  15. package/src/shade/renderer/atmosphere/ATMOSPHERE_PARAMETERS_STRUCT.d.ts.map +1 -0
  16. package/src/shade/renderer/atmosphere/ATMOSPHERE_PARAMETERS_STRUCT.js +160 -0
  17. package/src/shade/renderer/atmosphere/ATMOSPHERE_UNIT_SCALE.d.ts +45 -0
  18. package/src/shade/renderer/atmosphere/ATMOSPHERE_UNIT_SCALE.d.ts.map +1 -0
  19. package/src/shade/renderer/atmosphere/ATMOSPHERE_UNIT_SCALE.js +57 -0
  20. package/src/shade/renderer/atmosphere/GPUSky.d.ts +23 -8
  21. package/src/shade/renderer/atmosphere/GPUSky.d.ts.map +1 -1
  22. package/src/shade/renderer/atmosphere/GPUSky.js +91 -34
  23. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts +17 -0
  24. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.d.ts.map +1 -1
  25. package/src/shade/renderer/atmosphere/SAMPLER_SKY_LUT.js +55 -25
  26. package/src/shade/renderer/atmosphere/SceneAtmosphere.d.ts +164 -0
  27. package/src/shade/renderer/atmosphere/SceneAtmosphere.d.ts.map +1 -0
  28. package/src/shade/renderer/atmosphere/SceneAtmosphere.js +308 -0
  29. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts +3 -12
  30. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.d.ts.map +1 -1
  31. package/src/shade/renderer/atmosphere/chunk_get_multiscatter_values.js +52 -89
  32. package/src/shade/renderer/atmosphere/chunk_raymarch_sky_scattering.d.ts +14 -0
  33. package/src/shade/renderer/atmosphere/chunk_raymarch_sky_scattering.d.ts.map +1 -0
  34. package/src/shade/renderer/atmosphere/chunk_raymarch_sky_scattering.js +103 -0
  35. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts +10 -4
  36. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.d.ts.map +1 -1
  37. package/src/shade/renderer/atmosphere/chunk_sample_multiscatter_lut.js +95 -57
  38. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts +10 -14
  39. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.d.ts.map +1 -1
  40. package/src/shade/renderer/atmosphere/chunk_sample_transmittance_lut.js +97 -69
  41. package/src/shade/renderer/atmosphere/chunk_sky_irradiance_lut_encode_uv.d.ts +17 -0
  42. package/src/shade/renderer/atmosphere/chunk_sky_irradiance_lut_encode_uv.d.ts.map +1 -1
  43. package/src/shade/renderer/atmosphere/chunk_sky_irradiance_lut_encode_uv.js +117 -48
  44. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts +8 -0
  45. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.d.ts.map +1 -1
  46. package/src/shade/renderer/atmosphere/chunk_sky_lut_compute_uv.js +65 -35
  47. package/src/shade/renderer/atmosphere/compute_mie_absorption.d.ts +2 -1
  48. package/src/shade/renderer/atmosphere/compute_mie_absorption.d.ts.map +1 -1
  49. package/src/shade/renderer/atmosphere/compute_mie_absorption.js +6 -6
  50. package/src/shade/renderer/atmosphere/resolve_atmosphere_sun.d.ts +41 -0
  51. package/src/shade/renderer/atmosphere/resolve_atmosphere_sun.d.ts.map +1 -0
  52. package/src/shade/renderer/atmosphere/resolve_atmosphere_sun.js +123 -0
  53. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.d.ts.map +1 -1
  54. package/src/shade/renderer/atmosphere/shader_multiscatter_lut.js +21 -64
  55. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts +6 -2
  56. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.d.ts.map +1 -1
  57. package/src/shade/renderer/atmosphere/shader_sky_irradiance_lut.js +55 -179
  58. package/src/shade/renderer/atmosphere/shader_sky_view_lut.d.ts +7 -0
  59. package/src/shade/renderer/atmosphere/shader_sky_view_lut.d.ts.map +1 -0
  60. package/src/shade/renderer/atmosphere/shader_sky_view_lut.js +111 -0
  61. package/src/shade/renderer/atmosphere/shader_transmittance_lut.d.ts +0 -1
  62. package/src/shade/renderer/atmosphere/shader_transmittance_lut.d.ts.map +1 -1
  63. package/src/shade/renderer/atmosphere/shader_transmittance_lut.js +68 -79
  64. package/src/shade/renderer/deferred/shader_background.js +1 -1
  65. package/src/shade/renderer/deferred/shader_background_sky.d.ts +5 -0
  66. package/src/shade/renderer/deferred/shader_background_sky.d.ts.map +1 -0
  67. package/src/shade/renderer/deferred/shader_background_sky.js +130 -0
  68. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.d.ts +2 -1
  69. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.d.ts.map +1 -1
  70. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.js +6 -2
  71. package/src/shade/renderer/extension/ViewTextures.d.ts +3 -2
  72. package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
  73. package/src/shade/renderer/extension/ViewTextures.js +3 -2
  74. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  75. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  76. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  77. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  78. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  79. package/src/shade/renderer/global_illumination/probe/octahedral/shader_lpv_build_gbuffer.js +1 -1
  80. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +20 -1
  81. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  82. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +29 -0
  83. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_light.d.ts +47 -0
  84. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_light.d.ts.map +1 -0
  85. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_light.js +246 -0
  86. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts +4 -15
  87. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts.map +1 -1
  88. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +8 -148
  89. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts +4 -9
  90. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  91. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +9 -58
  92. package/src/shade/renderer/global_illumination/screen_probe/GPUScreenProbeGI.d.ts +142 -0
  93. package/src/shade/renderer/global_illumination/screen_probe/GPUScreenProbeGI.d.ts.map +1 -0
  94. package/src/shade/renderer/global_illumination/screen_probe/GPUScreenProbeGI.js +938 -0
  95. package/src/shade/renderer/global_illumination/screen_probe/SCREEN_PROBE.d.ts +192 -0
  96. package/src/shade/renderer/global_illumination/screen_probe/SCREEN_PROBE.d.ts.map +1 -0
  97. package/src/shade/renderer/global_illumination/screen_probe/SCREEN_PROBE.js +231 -0
  98. package/src/shade/renderer/global_illumination/screen_probe/ScreenProbeDebugView.d.ts +11 -0
  99. package/src/shade/renderer/global_illumination/screen_probe/ScreenProbeDebugView.d.ts.map +1 -0
  100. package/src/shade/renderer/global_illumination/screen_probe/ScreenProbeDebugView.js +25 -0
  101. package/src/shade/renderer/global_illumination/screen_probe/ScreenProbeSettings.d.ts +110 -0
  102. package/src/shade/renderer/global_illumination/screen_probe/ScreenProbeSettings.d.ts.map +1 -0
  103. package/src/shade/renderer/global_illumination/screen_probe/ScreenProbeSettings.js +197 -0
  104. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe.d.ts +150 -0
  105. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe.d.ts.map +1 -0
  106. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe.js +408 -0
  107. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_brdf_density.d.ts +23 -0
  108. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_brdf_density.d.ts.map +1 -0
  109. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_brdf_density.js +63 -0
  110. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_brick_origin.d.ts +24 -0
  111. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_brick_origin.d.ts.map +1 -0
  112. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_brick_origin.js +61 -0
  113. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_interpolate.d.ts +39 -0
  114. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_interpolate.d.ts.map +1 -0
  115. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_interpolate.js +126 -0
  116. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_lighting_history.d.ts +21 -0
  117. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_lighting_history.d.ts.map +1 -0
  118. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_lighting_history.js +74 -0
  119. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_march_distance.d.ts +20 -0
  120. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_march_distance.d.ts.map +1 -0
  121. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_march_distance.js +26 -0
  122. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_ray_sort.d.ts +24 -0
  123. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_ray_sort.d.ts.map +1 -0
  124. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_ray_sort.js +57 -0
  125. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_screen_march.d.ts +22 -0
  126. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_screen_march.d.ts.map +1 -0
  127. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_screen_march.js +53 -0
  128. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_surface.d.ts +62 -0
  129. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_surface.d.ts.map +1 -0
  130. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_surface.js +156 -0
  131. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_workgroup_sum.d.ts +18 -0
  132. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_workgroup_sum.d.ts.map +1 -0
  133. package/src/shade/renderer/global_illumination/screen_probe/chunk_screen_probe_workgroup_sum.js +50 -0
  134. package/src/shade/renderer/global_illumination/screen_probe/graph_screen_probe_debug_view.d.ts +21 -0
  135. package/src/shade/renderer/global_illumination/screen_probe/graph_screen_probe_debug_view.d.ts.map +1 -0
  136. package/src/shade/renderer/global_illumination/screen_probe/graph_screen_probe_debug_view.js +54 -0
  137. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_brick.d.ts +67 -0
  138. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_brick.d.ts.map +1 -0
  139. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_brick.js +509 -0
  140. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_debug.d.ts +20 -0
  141. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_debug.d.ts.map +1 -0
  142. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_debug.js +128 -0
  143. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_gather.d.ts +62 -0
  144. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_gather.d.ts.map +1 -0
  145. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_gather.js +478 -0
  146. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_importance.d.ts +69 -0
  147. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_importance.d.ts.map +1 -0
  148. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_importance.js +457 -0
  149. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_indirect_lighting.d.ts +27 -0
  150. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_indirect_lighting.d.ts.map +1 -0
  151. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_indirect_lighting.js +219 -0
  152. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_pick.d.ts +22 -0
  153. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_pick.d.ts.map +1 -0
  154. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_pick.js +151 -0
  155. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_place.d.ts +66 -0
  156. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_place.d.ts.map +1 -0
  157. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_place.js +301 -0
  158. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_resolve.d.ts +59 -0
  159. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_resolve.d.ts.map +1 -0
  160. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_resolve.js +364 -0
  161. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_trace_screen.d.ts +40 -0
  162. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_trace_screen.d.ts.map +1 -0
  163. package/src/shade/renderer/global_illumination/screen_probe/shader_screen_probe_trace_screen.js +275 -0
  164. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -1
  165. package/src/shade/renderer/grass/blade/GPUGrassBlades.js +17 -2
  166. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +18 -8
  167. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -1
  168. package/src/shade/renderer/grass/blade/grass_blade_resolve.js +114 -32
  169. package/src/shade/renderer/light/GPULightCollection.d.ts +1 -1
  170. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  171. package/src/shade/renderer/light/GPULightCollection.js +213 -80
  172. package/src/shade/renderer/{atmosphere → light/environment}/chunk_sample_environment_color.d.ts +1 -2
  173. package/src/shade/renderer/light/environment/chunk_sample_environment_color.d.ts.map +1 -0
  174. package/src/shade/renderer/{atmosphere → light/environment}/chunk_sample_environment_color.js +3 -4
  175. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  176. package/src/shade/renderer/path_tracer/shader/chunk_render_trace_path.js +1 -1
  177. package/src/shade/renderer/postprocess/denoise/debug/graph_pass_debug_reprojection.js +1 -1
  178. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts +1 -1
  179. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +1 -1
  180. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts +1 -1
  181. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.js +1 -1
  182. package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.js +1 -1
  183. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  184. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.js +2 -0
  185. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.js +2 -0
  186. package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.d.ts +6 -0
  187. package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.d.ts.map +1 -1
  188. package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.js +9 -1
  189. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts.map +1 -1
  190. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.js +4 -3
  191. package/src/shade/renderer/postprocess/velocity/VELOCITY_BUFFER.d.ts +17 -0
  192. package/src/shade/renderer/postprocess/velocity/VELOCITY_BUFFER.d.ts.map +1 -0
  193. package/src/shade/renderer/postprocess/velocity/VELOCITY_BUFFER.js +16 -0
  194. package/src/shade/renderer/postprocess/velocity/chunk_velocity_texel.d.ts +21 -0
  195. package/src/shade/renderer/postprocess/velocity/chunk_velocity_texel.d.ts.map +1 -0
  196. package/src/shade/renderer/postprocess/velocity/chunk_velocity_texel.js +30 -0
  197. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts +7 -5
  198. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  199. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +19 -17
  200. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.js +2 -0
  201. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  202. package/src/shade/renderer/scene/GPUSceneContext.js +2 -1
  203. package/src/shade/renderer/scene/Scene.d.ts +9 -2
  204. package/src/shade/renderer/scene/Scene.d.ts.map +1 -1
  205. package/src/shade/renderer/scene/Scene.js +10 -2
  206. package/src/shade/renderer/shader/ImageShader.d.ts +24 -12
  207. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  208. package/src/shade/renderer/shader/ImageShader.js +11 -8
  209. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_HEIGHT_DECLARATION.d.ts +3 -1
  210. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_HEIGHT_DECLARATION.d.ts.map +1 -1
  211. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_HEIGHT_DECLARATION.js +11 -3
  212. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts +2 -11
  213. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.d.ts.map +1 -1
  214. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_RADII_DECLARATION.js +23 -32
  215. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_RADIUS_DECLARATION.d.ts +6 -0
  216. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_RADIUS_DECLARATION.d.ts.map +1 -1
  217. package/src/shade/renderer/shader/chunk/atmosphere/PLANET_RADIUS_DECLARATION.js +14 -2
  218. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_height.d.ts.map +1 -1
  219. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_height.js +4 -2
  220. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_intersection.d.ts.map +1 -1
  221. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_intersection.js +11 -3
  222. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.d.ts.map +1 -1
  223. package/src/shade/renderer/shader/chunk/atmosphere/chunk_atmosphere_ray_bounds.js +68 -69
  224. package/src/shade/renderer/shader/chunk/atmosphere/chunk_get_sun_transmittance.d.ts +4 -1
  225. package/src/shade/renderer/shader/chunk/atmosphere/chunk_get_sun_transmittance.d.ts.map +1 -1
  226. package/src/shade/renderer/shader/chunk/atmosphere/chunk_get_sun_transmittance.js +46 -39
  227. package/src/shade/renderer/shader/chunk/atmosphere/chunk_position_relative_to_planet_center.d.ts.map +1 -1
  228. package/src/shade/renderer/shader/chunk/atmosphere/chunk_position_relative_to_planet_center.js +5 -3
  229. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.d.ts +18 -10
  230. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.d.ts.map +1 -1
  231. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.js +30 -27
  232. package/src/shade/renderer/shader/chunk/depth/chunk_get_device_depth.d.ts +14 -0
  233. package/src/shade/renderer/shader/chunk/depth/chunk_get_device_depth.d.ts.map +1 -0
  234. package/src/shade/renderer/shader/chunk/depth/chunk_get_device_depth.js +30 -0
  235. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_equal_area_sphere.d.ts +21 -0
  236. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_equal_area_sphere.d.ts.map +1 -0
  237. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_uv_equal_area_sphere.js +60 -0
  238. package/src/shade/renderer/shader/chunk/light/{sky/chunk_sample_sky_color.d.ts → io/chunk_light_get_sun.d.ts} +3 -6
  239. package/src/shade/renderer/shader/chunk/light/io/chunk_light_get_sun.d.ts.map +1 -0
  240. package/src/shade/renderer/shader/chunk/light/{sky/chunk_sample_sky_color.js → io/chunk_light_get_sun.js} +6 -26
  241. package/src/shade/renderer/shadow/sdf/cascade/shader_scene_sdf_soft_shadows.js +1 -1
  242. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +3 -1
  243. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  244. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +4 -2
  245. package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
  246. package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +743 -739
  247. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +2 -0
  248. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  249. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +19 -17
  250. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.d.ts.map +1 -1
  251. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +5 -3
  252. package/src/shade/renderer/water/chunk_water_gi.js +2 -0
  253. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  254. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  255. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.d.ts +0 -2
  256. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.d.ts.map +0 -1
  257. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.js +0 -45
  258. package/src/engine/graphics/sh3/path_tracer/make_sky_rtiw.d.ts +0 -2
  259. package/src/engine/graphics/sh3/path_tracer/make_sky_rtiw.d.ts.map +0 -1
  260. package/src/engine/graphics/sh3/path_tracer/make_sky_rtiw.js +0 -17
  261. package/src/engine/graphics/sh3/sky/hosek/README.md +0 -4
  262. package/src/engine/graphics/sh3/sky/hosek/data.d.ts +0 -17
  263. package/src/engine/graphics/sh3/sky/hosek/data.d.ts.map +0 -1
  264. package/src/engine/graphics/sh3/sky/hosek/data.js +0 -3744
  265. package/src/engine/graphics/sh3/sky/hosek/prototype_hosek.d.ts +0 -2
  266. package/src/engine/graphics/sh3/sky/hosek/prototype_hosek.d.ts.map +0 -1
  267. package/src/engine/graphics/sh3/sky/hosek/prototype_hosek.js +0 -71
  268. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts +0 -26
  269. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts.map +0 -1
  270. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js +0 -70
  271. package/src/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.d.ts +0 -22
  272. package/src/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.d.ts.map +0 -1
  273. package/src/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +0 -388
  274. package/src/engine/graphics3/make_default_environment.d.ts +0 -15
  275. package/src/engine/graphics3/make_default_environment.d.ts.map +0 -1
  276. package/src/engine/graphics3/make_default_environment.js +0 -111
  277. package/src/shade/renderer/atmosphere/MIE_G.d.ts +0 -6
  278. package/src/shade/renderer/atmosphere/MIE_G.d.ts.map +0 -1
  279. package/src/shade/renderer/atmosphere/MIE_G.js +0 -5
  280. package/src/shade/renderer/atmosphere/chunk_sample_environment_color.d.ts.map +0 -1
  281. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_EARTH.d.ts +0 -4
  282. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_EARTH.d.ts.map +0 -1
  283. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_EARTH.js +0 -44
  284. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_PARAMETERS_STRUCT.d.ts +0 -2
  285. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_PARAMETERS_STRUCT.d.ts.map +0 -1
  286. package/src/shade/renderer/atmosphere/hillaire/ATMOSPHERE_PARAMETERS_STRUCT.js +0 -43
  287. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_DENSITY_DECLARATION.d.ts +0 -3
  288. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_DENSITY_DECLARATION.d.ts.map +0 -1
  289. package/src/shade/renderer/shader/chunk/atmosphere/ATMOSPHERE_DENSITY_DECLARATION.js +0 -6
  290. package/src/shade/renderer/shader/chunk/atmosphere/chunk_absorb.d.ts +0 -3
  291. package/src/shade/renderer/shader/chunk/atmosphere/chunk_absorb.d.ts.map +0 -1
  292. package/src/shade/renderer/shader/chunk/atmosphere/chunk_absorb.js +0 -18
  293. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_optical_depth.d.ts +0 -14
  294. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_optical_depth.d.ts.map +0 -1
  295. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_optical_depth.js +0 -86
  296. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.d.ts +0 -8
  297. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.d.ts.map +0 -1
  298. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.js +0 -125
  299. package/src/shade/renderer/shader/chunk/atmosphere/chunk_planet_intersection.d.ts +0 -3
  300. package/src/shade/renderer/shader/chunk/atmosphere/chunk_planet_intersection.d.ts.map +0 -1
  301. package/src/shade/renderer/shader/chunk/atmosphere/chunk_planet_intersection.js +0 -17
  302. package/src/shade/renderer/shader/chunk/atmosphere/chunk_sphere_intersection_nearest.d.ts +0 -3
  303. package/src/shade/renderer/shader/chunk/atmosphere/chunk_sphere_intersection_nearest.d.ts.map +0 -1
  304. package/src/shade/renderer/shader/chunk/atmosphere/chunk_sphere_intersection_nearest.js +0 -38
  305. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.d.ts +0 -16
  306. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.d.ts.map +0 -1
  307. package/src/shade/renderer/shader/chunk/atmosphere/hillaire/DENSITY_PROFILE_LAYER_STRUCT.js +0 -28
  308. package/src/shade/renderer/shader/chunk/light/sky/chunk_sample_sky_color.d.ts.map +0 -1
  309. package/src/shade/renderer/view/GPUViewSkyContext.d.ts +0 -26
  310. package/src/shade/renderer/view/GPUViewSkyContext.d.ts.map +0 -1
  311. package/src/shade/renderer/view/GPUViewSkyContext.js +0 -170
@@ -1,739 +1,743 @@
1
- import { assert } from "../../../core/assert.js";
2
- import { SamplerDescriptor } from "../../descriptor/texture/SamplerDescriptor.js";
3
- import { BufferResourceDescriptor } from "../../device/graph/BufferResourceDescriptor.js";
4
- import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
5
- import { ShaderSwitchSet } from "../shader/compiler/ShaderSwitchSet.js";
6
- import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
7
- import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
8
- import { graph_import_texture } from "../shader/graph/graph_import_texture.js";
9
- import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
10
- import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
11
- import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
12
- import { SAMPLER_LINEAR_UPSCALE } from "../texture/SAMPLER_LINEAR_UPSCALE.js";
13
- import { WIND_FIELD_UNIFORM } from "../wind/WIND_FIELD_UNIFORM.js";
14
- import { VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION } from "./chunk_volumetrics_media_group_list.js";
15
- import { VOLUMETRICS_SUN_SHADOW_BRICK_Z } from "./chunk_volumetrics_sun_shadow_group_list.js";
16
- import { volumetrics_sun_shadow_texture_name } from "./chunk_volumetrics_sun_optical_depth.js";
17
- import { PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR } from "./noise/PARTICIPATING_MEDIA_NOISE.js";
18
- import { shader_volumetrics_bin_participating_media } from "./shader_volumetrics_bin_participating_media.js";
19
- import { shader_volumetrics_bin_sun_shadow_media } from "./shader_volumetrics_bin_sun_shadow_media.js";
20
- import { shader_volumetrics_build_lighting } from "./shader_volumetrics_build_lighting.js";
21
- import { shader_volumetrics_build_participating_media } from "./shader_volumetrics_build_participating_media.js";
22
- import { shader_volumetrics_build_scattering_lut } from "./shader_volumetrics_build_scattering_lut.js";
23
- import {
24
- shader_volumetrics_build_sun_shadow_volume_outermost,
25
- shader_volumetrics_build_sun_shadow_volume_seeded
26
- } from "./shader_volumetrics_build_sun_shadow_volume.js";
27
- import {
28
- shader_volumetrics_cull_sun_shadow_media,
29
- VOLUMETRICS_SUN_SHADOW_CULL_LANES
30
- } from "./shader_volumetrics_cull_sun_shadow_media.js";
31
- import {
32
- shader_volumetrics_split_participating_media,
33
- VOLUMETRICS_MEDIA_SPLIT_LANES
34
- } from "./shader_volumetrics_split_participating_media.js";
35
- import { shader_volumetrics_taa } from "./taa/shader_volumetrics_taa.js";
36
- import {
37
- VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
38
- VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
39
- volumetrics_sun_shadow_sub_steps
40
- } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
41
-
42
- /**
43
- *
44
- * @param {Object} options
45
- * @param {FrameGraph} options.graph
46
- * @param {GPUCameraContext} options.camera
47
- * @param {GPUSceneContext} options.scene
48
- * @param {GPUViewContext} options.view
49
- * @param {number} options.volumetrics_metadata
50
- * @param {number[]} options.resolution output resolution
51
- * @param {ShaderSwitchSet} options.shader_switches the renderer's; the build adds the wind field's shape
52
- */
53
- function graph_integrate_participating_media({
54
- graph,
55
- camera,
56
- scene,
57
- view,
58
- volumetrics_metadata,
59
- resolution,
60
- shader_switches,
61
- }) {
62
-
63
- const data = {};
64
-
65
- // the media build's workgroups, each of which the bin gives a list of the volumes it may see
66
- const groups = [
67
- Math.ceil(resolution[0] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[0]),
68
- Math.ceil(resolution[1] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[1]),
69
- resolution[2],
70
- ];
71
-
72
- // A bit a volume. Sized from the scene's volumes, which the table's rows never outnumber; the
73
- // shaders take the volume count off the table and the words a list gets off this buffer.
74
- const volume_count = scene.volumetrics.source.volumes.length;
75
- const list_words = Math.ceil(volume_count / 32);
76
- const group_lists_bytes = 4 * Math.max(4, groups[0] * groups[1] * groups[2] * list_words);
77
-
78
- // the near and the far field: a count, then a row for every volume either may hold
79
- const field_bytes = 4 * Math.max(4, 1 + volume_count);
80
-
81
- const pass = graph.add(
82
- "aerial lut",
83
- data,
84
- /**
85
- *
86
- * @param {} data
87
- * @param {FramePassResources} resources
88
- * @param {GraphicsExecutionContext} context
89
- */
90
- (data, resources, context) => {
91
-
92
- /**
93
- * @type {GPUTextureContext}
94
- */
95
- const output0 = resources.get(data.output0);
96
- /**
97
- * @type {GPUTextureContext}
98
- */
99
- const output1 = resources.get(data.output1);
100
-
101
- const group_lists = resources.get(data.group_lists);
102
- const near_field = resources.get(data.near_field);
103
- const far_field = resources.get(data.far_field);
104
-
105
- const encoder = context.encoder;
106
-
107
- const volumetrics_metadata = resources.get(data.volumetrics_metadata);
108
-
109
- shader_volumetrics_split_participating_media.dispatch({
110
- encoder,
111
- bindings: {
112
- camera: camera.buffer.buffer,
113
- volumetrics_metadata,
114
- scene_database: scene.scene_database_buffer,
115
- near_field,
116
- far_field,
117
- },
118
- group_count_x: Math.max(1, Math.ceil(volume_count / VOLUMETRICS_MEDIA_SPLIT_LANES)),
119
- });
120
-
121
- shader_volumetrics_bin_participating_media.dispatch({
122
- encoder,
123
- bindings: {
124
- camera: camera.buffer.buffer,
125
- volumetrics_metadata,
126
- scene_database: scene.scene_database_buffer,
127
- near_field,
128
- group_lists,
129
- },
130
- group_count_x: groups[0],
131
- group_count_y: groups[1],
132
- group_count_z: groups[2],
133
- });
134
-
135
- /**
136
- * The scene's noise atlas, imported this frame so a grow between frames is seen.
137
- * @type {GPUTextureContext}
138
- */
139
- const noise_atlas = resources.get(data.noise_atlas);
140
-
141
- // the per-froxel point the noise is read at moves by this volume every frame
142
- const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
143
-
144
- const bindings = {
145
- camera: camera.buffer.buffer,
146
- view: view.uniform_buffer.buffer,
147
- volumetrics_metadata,
148
- scene_database: scene.scene_database_buffer,
149
- tSTBN_vec3: tSTBN_vec3.obtainView(),
150
- tParticipatingMediaNoise: noise_atlas.obtainView(),
151
- sParticipatingMediaNoise: context.graphics.samplers.obtain(PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR),
152
- tOutput0: output0.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
153
- tOutput1: output1.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
154
- group_lists,
155
- };
156
-
157
- // taken this frame rather than held: a producer that grows the field replaces its atlas
158
- scene.wind.bind(bindings);
159
-
160
- // and read in the shape it has this frame: with no cascades the wind is the far field
161
- // everywhere, and that variant links neither the cascades' read nor the noise's flow map
162
- const switches = shader_switches.with(WIND_FIELD_UNIFORM, scene.wind.cascade_count === 0);
163
-
164
- shader_volumetrics_build_participating_media.variant(switches).dispatchThreads({
165
- encoder,
166
- thread_count_x: output0.width,
167
- thread_count_y: output0.height,
168
- thread_count_z: output0.depth,
169
- bindings,
170
- });
171
-
172
-
173
- });
174
-
175
- data.volumetrics_metadata = pass.read(volumetrics_metadata);
176
- // the split appends to lists counted from zero
177
- data.near_field = pass.create("participating media near field", BufferResourceDescriptor.from(
178
- field_bytes,
179
- GPUBufferUsage.STORAGE,
180
- 0, 4,
181
- ));
182
- data.far_field = pass.create("participating media far field", BufferResourceDescriptor.from(
183
- field_bytes,
184
- GPUBufferUsage.STORAGE,
185
- 0, 4,
186
- ));
187
- // the bin ORs bits into zeroed lists
188
- data.group_lists = pass.create("participating media group lists", BufferResourceDescriptor.from(
189
- group_lists_bytes,
190
- GPUBufferUsage.STORAGE,
191
- 0, group_lists_bytes,
192
- ));
193
- data.noise_atlas = pass.read(graph_import_texture(graph, scene.volumetrics.noise_atlas.texture, "volumetrics noise atlas"));
194
-
195
- data.output0 = pass.create("Participating Media 0", TextureResourceDescriptor.from({
196
- resolution,
197
- dimension: "3d",
198
- format: "rgba16float",
199
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
200
- }));
201
- data.output1 = pass.create("Participating Media 1", TextureResourceDescriptor.from({
202
- resolution,
203
- dimension: "3d",
204
- format: "rgba16float",
205
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
206
- }));
207
-
208
- return {
209
- participating_media0: data.output0,
210
- participating_media1: data.output1,
211
- volumetrics_metadata: data.volumetrics_metadata,
212
- far_field: data.far_field,
213
- };
214
- }
215
-
216
- /**
217
- * Q-04 / Q-05. The sun's optical depth, integrated once per frame into cascaded light-aligned
218
- * volumes directly from the scene's world-space participating-media volumes so the lighting pass
219
- * can read it in a single fetch without clipping shadow rays to the camera frustum.
220
- *
221
- * The cascades are ordered among themselves because each inner cascade is seeded from the value the
222
- * cascade outside it already computed at its entry face: the outermost is built first (including
223
- * its upwind half-space `w <= 0`) and the handle it returns is what makes the next pass wait for it.
224
- *
225
- * A texture per cascade rather than one texture with the cascades stacked along w. Stacking would
226
- * put a pass's own output and its input in the same texture, which WebGPU rejects — a subresource
227
- * cannot be bound as writable storage and as a sampled texture at once — and there is no
228
- * subresource finer than the whole 3D texture to split it on.
229
- *
230
- * Always present, even with the mode off — the volumes are then dispatched at 1x1x1 (see
231
- * `GPUViewVolumetrics`), which keeps the graph's topology identical on both sides of the A/B.
232
- *
233
- * @param {Object} options
234
- * @param {FrameGraph} options.graph
235
- * @param {GPUSceneContext} options.scene
236
- * @param {number} options.volumetrics_metadata
237
- * @param {number[]} options.resolution voxel counts of one cascade
238
- * @param {ShaderSwitchSet} options.shader_switches the renderer's; the build adds the wind field's shape
239
- * @returns {number[]} handles of the cascades, innermost first
240
- */
241
- function graph_build_sun_shadow_volume({
242
- graph,
243
- scene,
244
- volumetrics_metadata,
245
- resolution,
246
- shader_switches,
247
- }) {
248
-
249
- const group_count = [
250
- // one invocation per COLUMN along the sun axis, so only x and y are dispatched
251
- Math.ceil(resolution[0] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[0]),
252
- Math.ceil(resolution[1] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[1]),
253
- 1,
254
- ];
255
-
256
- const interior_bricks_z = Math.ceil(resolution[2] / VOLUMETRICS_SUN_SHADOW_BRICK_Z);
257
- const groups = [
258
- group_count[0],
259
- group_count[1],
260
- interior_bricks_z + 1,
261
- ];
262
-
263
- const volume_count = scene.volumetrics.source.volumes.length;
264
- const list_words = Math.ceil(volume_count / 32);
265
- const group_lists_bytes = 4 * Math.max(4, groups[0] * groups[1] * groups[2] * list_words);
266
- const field_bytes = 4 * Math.max(4, 1 + volume_count);
267
-
268
- const noise_atlas = graph_import_texture(graph, scene.volumetrics.noise_atlas.texture, "volumetrics sun shadow noise atlas");
269
-
270
- const cascades = [];
271
-
272
- for (let cascade = VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1; cascade >= 0; cascade--) {
273
-
274
- // Every cascade but the outermost starts its scan from the one outside it — which the
275
- // descending loop has already added, and which is the one difference the two build shaders
276
- // exist for.
277
- const seeded = cascade < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
278
- const base_shader = seeded
279
- ? shader_volumetrics_build_sun_shadow_volume_seeded
280
- : shader_volumetrics_build_sun_shadow_volume_outermost;
281
-
282
- const data = {};
283
-
284
- const pass = graph.add(
285
- base_shader.descriptor.label,
286
- data,
287
- /**
288
- * @param {} data
289
- * @param {FramePassResources} resources
290
- * @param {GraphicsExecutionContext} context
291
- */
292
- (data, resources, context) => {
293
- /**
294
- * @type {GPUTextureContext}
295
- */
296
- const output = resources.get(data.output);
297
- const volumetrics_metadata = resources.get(data.volumetrics_metadata);
298
- const cascade_field = resources.get(data.cascade_field);
299
- const group_lists = resources.get(data.group_lists);
300
- /**
301
- * @type {GPUTextureContext}
302
- */
303
- const noise_atlas = resources.get(data.noise_atlas);
304
-
305
- const encoder = context.encoder;
306
-
307
- const bin_settings = {
308
- resolution,
309
- cascade,
310
- };
311
-
312
- shader_volumetrics_cull_sun_shadow_media.dispatch({
313
- encoder,
314
- bindings: {
315
- settings: bin_settings,
316
- volumetrics_metadata,
317
- scene_database: scene.scene_database_buffer,
318
- cascade_field,
319
- },
320
- group_count_x: Math.max(1, Math.ceil(volume_count / VOLUMETRICS_SUN_SHADOW_CULL_LANES)),
321
- });
322
-
323
- shader_volumetrics_bin_sun_shadow_media.dispatch({
324
- encoder,
325
- bindings: {
326
- settings: bin_settings,
327
- volumetrics_metadata,
328
- scene_database: scene.scene_database_buffer,
329
- cascade_field,
330
- group_lists,
331
- },
332
- group_count_x: groups[0],
333
- group_count_y: groups[1],
334
- group_count_z: seeded ? interior_bricks_z : groups[2],
335
- });
336
-
337
- const bindings = {
338
- settings: {
339
- cascade,
340
- sub_steps: volumetrics_sun_shadow_sub_steps(cascade),
341
- },
342
- volumetrics_metadata,
343
- scene_database: scene.scene_database_buffer,
344
- group_lists,
345
- tParticipatingMediaNoise: noise_atlas.obtainView(),
346
- sParticipatingMediaNoise: context.graphics.samplers.obtain(PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR),
347
- tSunShadowVolume: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
348
- };
349
-
350
- if (seeded) {
351
- const outer = resources.get(data.outer);
352
- bindings.sLinear = context.graphics.samplers.obtain(SAMPLER_LINEAR_UPSCALE);
353
- bindings.tSunShadowOuter = outer.obtainView();
354
- }
355
-
356
- scene.wind.bind(bindings);
357
-
358
- const switches = shader_switches.with(WIND_FIELD_UNIFORM, scene.wind.cascade_count === 0);
359
-
360
- base_shader.variant(switches).dispatch({
361
- encoder,
362
- bindings,
363
- group_count_x: group_count[0],
364
- group_count_y: group_count[1],
365
- group_count_z: group_count[2],
366
- });
367
- }
368
- );
369
-
370
- data.volumetrics_metadata = pass.read(volumetrics_metadata);
371
- data.noise_atlas = pass.read(noise_atlas);
372
-
373
- if (seeded) {
374
- data.outer = pass.read(cascades[cascade + 1]);
375
- }
376
-
377
- data.cascade_field = pass.create(`sun shadow cascade ${cascade} field`, BufferResourceDescriptor.from(
378
- field_bytes,
379
- GPUBufferUsage.STORAGE,
380
- 0, 4,
381
- ));
382
- data.group_lists = pass.create(`sun shadow cascade ${cascade} group lists`, BufferResourceDescriptor.from(
383
- group_lists_bytes,
384
- GPUBufferUsage.STORAGE,
385
- 0, group_lists_bytes,
386
- ));
387
- data.output = pass.create(`Sun Shadow Cascade ${cascade}`, TextureResourceDescriptor.from({
388
- resolution,
389
- dimension: "3d",
390
- format: "rgba16float",
391
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
392
- }));
393
-
394
- cascades[cascade] = data.output;
395
- }
396
-
397
- return cascades;
398
- }
399
-
400
- /**
401
- *
402
- * @param {FrameGraph} graph
403
- * @param participating_media0
404
- * @param participating_media1
405
- * @param volumetrics_metadata
406
- * @param light_cluster_data
407
- * @param light_cluster_lookup
408
- * @param light_cluster_parameters
409
- * @param shadowmap_atlas
410
- * @param sun_transmittance_lut
411
- * @param sun_multiple_scattering_lut
412
- * @param {number[]} sun_shadow_cascades handles of the Q-04 optical-depth cascades, innermost first
413
- * @param lights
414
- * @param view
415
- * @param camera
416
- * @param resolution
417
- * @param {ShaderSwitchSet} shader_switches the renderer's; the lighting pass is built for them
418
- * @returns {number} the lit scattering volume
419
- */
420
- function graph_integrate_light_scattering({
421
- graph,
422
- participating_media0,
423
- participating_media1,
424
- volumetrics_metadata,
425
- light_cluster_data,
426
- light_cluster_lookup,
427
- light_cluster_parameters,
428
- shadowmap_atlas,
429
- sun_transmittance_lut,
430
- sun_multiple_scattering_lut,
431
- sun_shadow_cascades,
432
- lights,
433
- view,
434
- camera,
435
- resolution,
436
- shader_switches,
437
- }) {
438
-
439
- const data = {};
440
-
441
- const pass = graph.add("scattering lut", data, (data, resources, context) => {
442
- const output = resources.get(data.output);
443
-
444
- const volumetrics_metadata = resources.get(data.volumetrics_metadata);
445
-
446
- const participating_media0 = resources.get(data.participating_media0);
447
- const participating_media1 = resources.get(data.participating_media1);
448
-
449
- const light_cluster_data = resources.get(data.light_cluster_data);
450
- const light_cluster_lookup = resources.get(data.light_cluster_lookup);
451
- const light_cluster_parameters = resources.get(data.light_cluster_parameters);
452
- const shadowmap_atlas = resources.get(data.shadowmap_atlas);
453
-
454
- const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
455
- const sun_multiple_scattering_lut = resources.get(data.sun_multiple_scattering_lut);
456
- const sun_shadow_cascades = data.sun_shadow_cascades.map(handle => resources.get(handle));
457
-
458
- const sampler_shadowmap = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
459
- const sLinear = context.graphics.samplers.obtain(SamplerDescriptor.from({
460
- magFilter: "linear",
461
- }));
462
-
463
- // Spatiotemporal blue noise for the per-froxel sample offset. The pass takes one sample and
464
- // leans on the volumetric TAA to integrate, which only works if each froxel's sequence over
465
- // frames is well distributed — the property a per-froxel hash does not have.
466
- const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
467
-
468
- const encoder = context.encoder;
469
-
470
- const bindings = {
471
- camera: camera.buffer.buffer,
472
- view: view.uniform_buffer.buffer,
473
- volumetrics_metadata,
474
- sLinear,
475
- tSunTransmittance: sun_transmittance_lut.obtainView(),
476
- tMultiScattering: sun_multiple_scattering_lut.obtainView(),
477
- tSTBN_vec3: tSTBN_vec3.obtainView(),
478
- tParticipatingMedia0: participating_media0.obtainView(),
479
- tParticipatingMedia1: participating_media1.obtainView(),
480
- tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
481
- //
482
- light_data: lights.buffer_data,
483
-
484
- cluster_data: light_cluster_data,
485
- cluster_lookup: light_cluster_lookup,
486
- cluster_parameters: light_cluster_parameters,
487
-
488
- shadowmapAtlas: shadowmap_atlas.obtainView(),
489
- sCompareLinear: sampler_shadowmap,
490
- };
491
-
492
- // One texture per cascade, under the names the read side declares. Bound here rather than
493
- // above because the count is a constant of the structure, not of this pass.
494
- for (let cascade = 0; cascade < sun_shadow_cascades.length; cascade++) {
495
- bindings[volumetrics_sun_shadow_texture_name(cascade)] = sun_shadow_cascades[cascade].obtainView();
496
- }
497
-
498
- shader_volumetrics_build_lighting.variant(shader_switches).dispatchThreads({
499
- encoder,
500
- thread_count_x: output.width,
501
- thread_count_y: output.height,
502
- thread_count_z: output.depth,
503
- bindings
504
- })
505
- });
506
-
507
- data.participating_media0 = pass.read(participating_media0);
508
- data.participating_media1 = pass.read(participating_media1);
509
- data.volumetrics_metadata = pass.read(volumetrics_metadata);
510
-
511
- data.shadowmap_atlas = pass.read(shadowmap_atlas);
512
- data.light_cluster_data = pass.read(light_cluster_data);
513
- data.light_cluster_lookup = pass.read(light_cluster_lookup);
514
- data.light_cluster_parameters = pass.read(light_cluster_parameters);
515
-
516
- data.sun_transmittance_lut = pass.read(sun_transmittance_lut);
517
- data.sun_multiple_scattering_lut = pass.read(sun_multiple_scattering_lut);
518
- data.sun_shadow_cascades = sun_shadow_cascades.map(handle => pass.read(handle));
519
-
520
- data.output = pass.create("Light Scattering LUT", TextureResourceDescriptor.from({
521
- resolution,
522
- dimension: "3d",
523
- format: "rgba16float",
524
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
525
- }));
526
-
527
- return data.output;
528
-
529
- }
530
-
531
- /**
532
- * The fog: participating media -> per-froxel lighting -> ray-marched integration into the aerial LUT
533
- * every surface behind it is seen through. Particle lighting is not here — it needs no medium, and
534
- * `GPUIrradianceClipmap` builds it on its own.
535
- *
536
- * @param {Object} options
537
- * @param {FrameGraph} options.graph
538
- * @param {GPUCameraContext} options.camera
539
- * @param {GPULightCollection} options.lights
540
- * @param {GPUViewContext} options.view
541
- * @param {GPUSky} options.sky the scene's sky, already {@link GPUSky#update updated}: its two
542
- * persistent LUTs are imported and read, not rebuilt. The sun's transmittance and the multiple
543
- * scattering depend on nothing but the atmosphere's constants, so building them again per frame
544
- * bought the same texels at a cost that was paid whether or not the scene had any fog.
545
- * @param {number} options.light_cluster_data
546
- * @param {number} options.light_cluster_lookup
547
- * @param {number} options.light_cluster_parameters
548
- * @param {number} options.shadowmap_atlas
549
- * @param {number[]} options.volumetric_resolution
550
- * @param {number[]} options.sun_shadow_resolution voxel counts of one Q-04 sun optical-depth cascade;
551
- * `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
552
- * doing any work
553
- * @param {number} options.volumetrics_metadata
554
- * @param {number} [options.taa_history] imported previous-frame accumulated scattering volume
555
- * @param {number} [options.taa_output] imported destination for this frame's accumulated scattering volume
556
- * @param {GPUCameraContext} [options.camera_previous] previous-frame camera, for temporal reprojection
557
- * @param {ShaderSwitchSet} [options.shader_switches] the renderer's; the lighting pass is built for them
558
- */
559
- export function graph_build_volumetrics({
560
- graph,
561
- camera,
562
- lights,
563
- view,
564
- sky,
565
- light_cluster_data,
566
- light_cluster_lookup,
567
- light_cluster_parameters,
568
- shadowmap_atlas,
569
- volumetric_resolution,
570
- sun_shadow_resolution,
571
- volumetrics_metadata,
572
- taa_history,
573
- taa_output,
574
- camera_previous,
575
- shader_switches = ShaderSwitchSet.EMPTY,
576
- }) {
577
-
578
- assert.defined(view, 'view');
579
- assert.defined(sky, 'sky');
580
- assert.equal(sky.needs_update, false, 'sky has not been updated, its LUTs hold nothing yet');
581
- assert.defined(volumetric_resolution, 'volumetric_resolution');
582
- assert.defined(sun_shadow_resolution, 'sun_shadow_resolution');
583
-
584
- graph.push_scope("build volumetrics");
585
-
586
- // Read-only here, so nothing in this graph orders against a write to either; the sky wrote
587
- // them in commands of its own, submitted before this frame's.
588
- const transmittance_lut = graph_import_texture(graph, sky.lut_transmittance);
589
- const multiscatted_lut = graph_import_texture(graph, sky.lut_multiple_scattering);
590
-
591
- const {
592
- participating_media0,
593
- participating_media1,
594
- far_field,
595
- } = graph_integrate_participating_media({
596
- graph,
597
- scene: view.scene,
598
- view,
599
- resolution: volumetric_resolution,
600
- volumetrics_metadata,
601
- camera,
602
- shader_switches,
603
- });
604
-
605
- const sun_shadow_cascades = graph_build_sun_shadow_volume({
606
- graph,
607
- scene: view.scene,
608
- volumetrics_metadata,
609
- resolution: sun_shadow_resolution,
610
- shader_switches,
611
- });
612
-
613
- const light_scattering_lut = graph_integrate_light_scattering({
614
- graph,
615
- resolution: volumetric_resolution,
616
- camera,
617
- view,
618
- sun_transmittance_lut: transmittance_lut,
619
- sun_multiple_scattering_lut: multiscatted_lut,
620
- sun_shadow_cascades,
621
- participating_media0,
622
- participating_media1,
623
- volumetrics_metadata,
624
- light_cluster_data,
625
- light_cluster_lookup,
626
- light_cluster_parameters,
627
- shadowmap_atlas,
628
- lights,
629
- shader_switches,
630
- });
631
-
632
- // Temporal reprojection of the per-froxel lit scattering volume, applied BEFORE aerial
633
- // integration — reprojecting the already-integrated aerial LUT would double-integrate along the
634
- // view ray. Optional: skipped when no history ping-pong is supplied (TAA disabled), in which
635
- // case the aerial pass consumes the raw (noisier) scattering LUT directly.
636
- let volume_lighting_resolved = light_scattering_lut;
637
-
638
- if (taa_history !== undefined && taa_output !== undefined) {
639
- const taa_outputs = graph_compute_pass({
640
- graph,
641
- shader: shader_volumetrics_taa,
642
- group_count: [
643
- Math.ceil(volumetric_resolution[0] / 8),
644
- Math.ceil(volumetric_resolution[1] / 8),
645
- Math.ceil(volumetric_resolution[2] / 4),
646
- ],
647
- bindings: {
648
- t_current: light_scattering_lut,
649
- t_history: taa_history,
650
- t_output: taa_output,
651
- volumetrics_metadata,
652
- camera_current: graph_import_buffer(graph, camera.buffer.buffer, "volumetrics taa camera"),
653
- camera_previous: graph_import_buffer(graph, camera_previous.buffer.buffer, "volumetrics taa camera previous"),
654
- },
655
- });
656
-
657
- volume_lighting_resolved = taa_outputs.t_output;
658
- }
659
-
660
- const a_data = {};
661
-
662
- const a_pass = graph.add("aerial lut", a_data, (data, resources, context) => {
663
- const output = resources.get(data.output);
664
-
665
- const participating_media0 = resources.get(data.participating_media0);
666
- const participating_media1 = resources.get(data.participating_media1);
667
- const volumetrics_metadata = resources.get(data.volumetrics_metadata);
668
-
669
- const light_scattering_lut = resources.get(data.light_scattering_lut);
670
- const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
671
- const far_field = resources.get(data.far_field);
672
-
673
- const encoder = context.encoder;
674
-
675
-
676
- const graphics = context.graphics;
677
-
678
- const sLinear = graphics.samplers.obtain(SamplerDescriptor.from({
679
- magFilter: "linear",
680
- }));
681
-
682
- const tSTBN_vec3 = graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
683
-
684
- shader_volumetrics_build_scattering_lut.dispatchThreads({
685
- encoder,
686
- thread_count_x: output.width,
687
- thread_count_y: output.height,
688
- bindings: {
689
- camera: camera.buffer.buffer,
690
- view: view.uniform_buffer.buffer,
691
- volumetrics_metadata,
692
- tSTBN_vec3: tSTBN_vec3.obtainView(),
693
- sLinear,
694
-
695
- tVolumeLighting: light_scattering_lut.obtainView(),
696
- tParticipatingMedia0: participating_media0.obtainView(),
697
- tParticipatingMedia1: participating_media1.obtainView(),
698
-
699
- // RDR2-style far-field march inputs (used beyond froxel_far)
700
- scene_database: view.scene.scene_database_buffer,
701
- far_field,
702
- light_data: lights.buffer_data,
703
- tSunTransmittance: sun_transmittance_lut.obtainView(),
704
-
705
- tOutput: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
706
- }
707
- });
708
-
709
-
710
- });
711
-
712
- a_data.participating_media0 = a_pass.read(participating_media0);
713
- a_data.participating_media1 = a_pass.read(participating_media1);
714
- a_data.volumetrics_metadata = a_pass.read(volumetrics_metadata);
715
- a_data.sun_transmittance_lut = a_pass.read(transmittance_lut);
716
- a_data.far_field = a_pass.read(far_field);
717
-
718
- a_data.output = a_pass.create("Integrated Volumetrics", TextureResourceDescriptor.from({
719
- resolution: volumetric_resolution,
720
- dimension: "3d",
721
- format: "rgba16float",
722
- usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
723
- }))
724
-
725
-
726
- a_data.light_scattering_lut = a_pass.read(volume_lighting_resolved);
727
-
728
-
729
- // TODO add temporal reprojection
730
-
731
- graph.pop_scope();
732
-
733
- return {
734
- lut_transmittance: transmittance_lut,
735
- lut_multiple_scattering: multiscatted_lut,
736
- lut_aerial: a_data.output,
737
- volumetrics_metadata,
738
- };
739
- }
1
+ import { assert } from "../../../core/assert.js";
2
+ import { SamplerDescriptor } from "../../descriptor/texture/SamplerDescriptor.js";
3
+ import { BufferResourceDescriptor } from "../../device/graph/BufferResourceDescriptor.js";
4
+ import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
5
+ import { ShaderSwitchSet } from "../shader/compiler/ShaderSwitchSet.js";
6
+ import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
7
+ import { graph_import_buffer } from "../shader/graph/graph_import_buffer.js";
8
+ import { graph_import_texture } from "../shader/graph/graph_import_texture.js";
9
+ import { SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR } from "../shadow/map/SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR.js";
10
+ import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
11
+ import { DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR } from "../texture/DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR.js";
12
+ import { SAMPLER_LINEAR_UPSCALE } from "../texture/SAMPLER_LINEAR_UPSCALE.js";
13
+ import { WIND_FIELD_UNIFORM } from "../wind/WIND_FIELD_UNIFORM.js";
14
+ import { VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION } from "./chunk_volumetrics_media_group_list.js";
15
+ import { VOLUMETRICS_SUN_SHADOW_BRICK_Z } from "./chunk_volumetrics_sun_shadow_group_list.js";
16
+ import { volumetrics_sun_shadow_texture_name } from "./chunk_volumetrics_sun_optical_depth.js";
17
+ import { PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR } from "./noise/PARTICIPATING_MEDIA_NOISE.js";
18
+ import { shader_volumetrics_bin_participating_media } from "./shader_volumetrics_bin_participating_media.js";
19
+ import { shader_volumetrics_bin_sun_shadow_media } from "./shader_volumetrics_bin_sun_shadow_media.js";
20
+ import { shader_volumetrics_build_lighting } from "./shader_volumetrics_build_lighting.js";
21
+ import { shader_volumetrics_build_participating_media } from "./shader_volumetrics_build_participating_media.js";
22
+ import { shader_volumetrics_build_scattering_lut } from "./shader_volumetrics_build_scattering_lut.js";
23
+ import {
24
+ shader_volumetrics_build_sun_shadow_volume_outermost,
25
+ shader_volumetrics_build_sun_shadow_volume_seeded
26
+ } from "./shader_volumetrics_build_sun_shadow_volume.js";
27
+ import {
28
+ shader_volumetrics_cull_sun_shadow_media,
29
+ VOLUMETRICS_SUN_SHADOW_CULL_LANES
30
+ } from "./shader_volumetrics_cull_sun_shadow_media.js";
31
+ import {
32
+ shader_volumetrics_split_participating_media,
33
+ VOLUMETRICS_MEDIA_SPLIT_LANES
34
+ } from "./shader_volumetrics_split_participating_media.js";
35
+ import { shader_volumetrics_taa } from "./taa/shader_volumetrics_taa.js";
36
+ import {
37
+ VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT,
38
+ VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION,
39
+ volumetrics_sun_shadow_sub_steps
40
+ } from "./VOLUMETRICS_SUN_SHADOW_RESOLUTION.js";
41
+
42
+ /**
43
+ *
44
+ * @param {Object} options
45
+ * @param {FrameGraph} options.graph
46
+ * @param {GPUCameraContext} options.camera
47
+ * @param {GPUSceneContext} options.scene
48
+ * @param {GPUViewContext} options.view
49
+ * @param {number} options.volumetrics_metadata
50
+ * @param {number[]} options.resolution output resolution
51
+ * @param {ShaderSwitchSet} options.shader_switches the renderer's; the build adds the wind field's shape
52
+ */
53
+ function graph_integrate_participating_media({
54
+ graph,
55
+ camera,
56
+ scene,
57
+ view,
58
+ volumetrics_metadata,
59
+ resolution,
60
+ shader_switches,
61
+ }) {
62
+
63
+ const data = {};
64
+
65
+ // the media build's workgroups, each of which the bin gives a list of the volumes it may see
66
+ const groups = [
67
+ Math.ceil(resolution[0] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[0]),
68
+ Math.ceil(resolution[1] / VOLUMETRICS_MEDIA_WORKGROUP_RESOLUTION[1]),
69
+ resolution[2],
70
+ ];
71
+
72
+ // A bit a volume. Sized from the scene's volumes, which the table's rows never outnumber; the
73
+ // shaders take the volume count off the table and the words a list gets off this buffer.
74
+ const volume_count = scene.volumetrics.source.volumes.length;
75
+ const list_words = Math.ceil(volume_count / 32);
76
+ const group_lists_bytes = 4 * Math.max(4, groups[0] * groups[1] * groups[2] * list_words);
77
+
78
+ // the near and the far field: a count, then a row for every volume either may hold
79
+ const field_bytes = 4 * Math.max(4, 1 + volume_count);
80
+
81
+ const pass = graph.add(
82
+ "aerial lut",
83
+ data,
84
+ /**
85
+ *
86
+ * @param {} data
87
+ * @param {FramePassResources} resources
88
+ * @param {GraphicsExecutionContext} context
89
+ */
90
+ (data, resources, context) => {
91
+
92
+ /**
93
+ * @type {GPUTextureContext}
94
+ */
95
+ const output0 = resources.get(data.output0);
96
+ /**
97
+ * @type {GPUTextureContext}
98
+ */
99
+ const output1 = resources.get(data.output1);
100
+
101
+ const group_lists = resources.get(data.group_lists);
102
+ const near_field = resources.get(data.near_field);
103
+ const far_field = resources.get(data.far_field);
104
+
105
+ const encoder = context.encoder;
106
+
107
+ const volumetrics_metadata = resources.get(data.volumetrics_metadata);
108
+
109
+ shader_volumetrics_split_participating_media.dispatch({
110
+ encoder,
111
+ bindings: {
112
+ camera: camera.buffer.buffer,
113
+ volumetrics_metadata,
114
+ scene_database: scene.scene_database_buffer,
115
+ near_field,
116
+ far_field,
117
+ },
118
+ group_count_x: Math.max(1, Math.ceil(volume_count / VOLUMETRICS_MEDIA_SPLIT_LANES)),
119
+ });
120
+
121
+ shader_volumetrics_bin_participating_media.dispatch({
122
+ encoder,
123
+ bindings: {
124
+ camera: camera.buffer.buffer,
125
+ volumetrics_metadata,
126
+ scene_database: scene.scene_database_buffer,
127
+ near_field,
128
+ group_lists,
129
+ },
130
+ group_count_x: groups[0],
131
+ group_count_y: groups[1],
132
+ group_count_z: groups[2],
133
+ });
134
+
135
+ /**
136
+ * The scene's noise atlas, imported this frame so a grow between frames is seen.
137
+ * @type {GPUTextureContext}
138
+ */
139
+ const noise_atlas = resources.get(data.noise_atlas);
140
+
141
+ // the per-froxel point the noise is read at moves by this volume every frame
142
+ const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
143
+
144
+ const bindings = {
145
+ camera: camera.buffer.buffer,
146
+ view: view.uniform_buffer.buffer,
147
+ volumetrics_metadata,
148
+ scene_database: scene.scene_database_buffer,
149
+ tSTBN_vec3: tSTBN_vec3.obtainView(),
150
+ tParticipatingMediaNoise: noise_atlas.obtainView(),
151
+ sParticipatingMediaNoise: context.graphics.samplers.obtain(PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR),
152
+ tOutput0: output0.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
153
+ tOutput1: output1.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
154
+ group_lists,
155
+ };
156
+
157
+ // taken this frame rather than held: a producer that grows the field replaces its atlas
158
+ scene.wind.bind(bindings);
159
+
160
+ // and read in the shape it has this frame: with no cascades the wind is the far field
161
+ // everywhere, and that variant links neither the cascades' read nor the noise's flow map
162
+ const switches = shader_switches.with(WIND_FIELD_UNIFORM, scene.wind.cascade_count === 0);
163
+
164
+ shader_volumetrics_build_participating_media.variant(switches).dispatchThreads({
165
+ encoder,
166
+ thread_count_x: output0.width,
167
+ thread_count_y: output0.height,
168
+ thread_count_z: output0.depth,
169
+ bindings,
170
+ });
171
+
172
+
173
+ });
174
+
175
+ data.volumetrics_metadata = pass.read(volumetrics_metadata);
176
+ // the split appends to lists counted from zero
177
+ data.near_field = pass.create("participating media near field", BufferResourceDescriptor.from(
178
+ field_bytes,
179
+ GPUBufferUsage.STORAGE,
180
+ 0, 4,
181
+ ));
182
+ data.far_field = pass.create("participating media far field", BufferResourceDescriptor.from(
183
+ field_bytes,
184
+ GPUBufferUsage.STORAGE,
185
+ 0, 4,
186
+ ));
187
+ // the bin ORs bits into zeroed lists
188
+ data.group_lists = pass.create("participating media group lists", BufferResourceDescriptor.from(
189
+ group_lists_bytes,
190
+ GPUBufferUsage.STORAGE,
191
+ 0, group_lists_bytes,
192
+ ));
193
+ data.noise_atlas = pass.read(graph_import_texture(graph, scene.volumetrics.noise_atlas.texture, "volumetrics noise atlas"));
194
+
195
+ data.output0 = pass.create("Participating Media 0", TextureResourceDescriptor.from({
196
+ resolution,
197
+ dimension: "3d",
198
+ format: "rgba16float",
199
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
200
+ }));
201
+ data.output1 = pass.create("Participating Media 1", TextureResourceDescriptor.from({
202
+ resolution,
203
+ dimension: "3d",
204
+ format: "rgba16float",
205
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
206
+ }));
207
+
208
+ return {
209
+ participating_media0: data.output0,
210
+ participating_media1: data.output1,
211
+ volumetrics_metadata: data.volumetrics_metadata,
212
+ far_field: data.far_field,
213
+ };
214
+ }
215
+
216
+ /**
217
+ * Q-04 / Q-05. The sun's optical depth, integrated once per frame into cascaded light-aligned
218
+ * volumes directly from the scene's world-space participating-media volumes so the lighting pass
219
+ * can read it in a single fetch without clipping shadow rays to the camera frustum.
220
+ *
221
+ * The cascades are ordered among themselves because each inner cascade is seeded from the value the
222
+ * cascade outside it already computed at its entry face: the outermost is built first (including
223
+ * its upwind half-space `w <= 0`) and the handle it returns is what makes the next pass wait for it.
224
+ *
225
+ * A texture per cascade rather than one texture with the cascades stacked along w. Stacking would
226
+ * put a pass's own output and its input in the same texture, which WebGPU rejects — a subresource
227
+ * cannot be bound as writable storage and as a sampled texture at once — and there is no
228
+ * subresource finer than the whole 3D texture to split it on.
229
+ *
230
+ * Always present, even with the mode off — the volumes are then dispatched at 1x1x1 (see
231
+ * `GPUViewVolumetrics`), which keeps the graph's topology identical on both sides of the A/B.
232
+ *
233
+ * @param {Object} options
234
+ * @param {FrameGraph} options.graph
235
+ * @param {GPUSceneContext} options.scene
236
+ * @param {number} options.volumetrics_metadata
237
+ * @param {number[]} options.resolution voxel counts of one cascade
238
+ * @param {ShaderSwitchSet} options.shader_switches the renderer's; the build adds the wind field's shape
239
+ * @returns {number[]} handles of the cascades, innermost first
240
+ */
241
+ function graph_build_sun_shadow_volume({
242
+ graph,
243
+ scene,
244
+ volumetrics_metadata,
245
+ resolution,
246
+ shader_switches,
247
+ }) {
248
+
249
+ const group_count = [
250
+ // one invocation per COLUMN along the sun axis, so only x and y are dispatched
251
+ Math.ceil(resolution[0] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[0]),
252
+ Math.ceil(resolution[1] / VOLUMETRICS_SUN_SHADOW_WORKGROUP_RESOLUTION[1]),
253
+ 1,
254
+ ];
255
+
256
+ const interior_bricks_z = Math.ceil(resolution[2] / VOLUMETRICS_SUN_SHADOW_BRICK_Z);
257
+ const groups = [
258
+ group_count[0],
259
+ group_count[1],
260
+ interior_bricks_z + 1,
261
+ ];
262
+
263
+ const volume_count = scene.volumetrics.source.volumes.length;
264
+ const list_words = Math.ceil(volume_count / 32);
265
+ const group_lists_bytes = 4 * Math.max(4, groups[0] * groups[1] * groups[2] * list_words);
266
+ const field_bytes = 4 * Math.max(4, 1 + volume_count);
267
+
268
+ const noise_atlas = graph_import_texture(graph, scene.volumetrics.noise_atlas.texture, "volumetrics sun shadow noise atlas");
269
+
270
+ const cascades = [];
271
+
272
+ for (let cascade = VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1; cascade >= 0; cascade--) {
273
+
274
+ // Every cascade but the outermost starts its scan from the one outside it — which the
275
+ // descending loop has already added, and which is the one difference the two build shaders
276
+ // exist for.
277
+ const seeded = cascade < VOLUMETRICS_SUN_SHADOW_CASCADE_COUNT - 1;
278
+ const base_shader = seeded
279
+ ? shader_volumetrics_build_sun_shadow_volume_seeded
280
+ : shader_volumetrics_build_sun_shadow_volume_outermost;
281
+
282
+ const data = {};
283
+
284
+ const pass = graph.add(
285
+ base_shader.descriptor.label,
286
+ data,
287
+ /**
288
+ * @param {} data
289
+ * @param {FramePassResources} resources
290
+ * @param {GraphicsExecutionContext} context
291
+ */
292
+ (data, resources, context) => {
293
+ /**
294
+ * @type {GPUTextureContext}
295
+ */
296
+ const output = resources.get(data.output);
297
+ const volumetrics_metadata = resources.get(data.volumetrics_metadata);
298
+ const cascade_field = resources.get(data.cascade_field);
299
+ const group_lists = resources.get(data.group_lists);
300
+ /**
301
+ * @type {GPUTextureContext}
302
+ */
303
+ const noise_atlas = resources.get(data.noise_atlas);
304
+
305
+ const encoder = context.encoder;
306
+
307
+ const bin_settings = {
308
+ resolution,
309
+ cascade,
310
+ };
311
+
312
+ shader_volumetrics_cull_sun_shadow_media.dispatch({
313
+ encoder,
314
+ bindings: {
315
+ settings: bin_settings,
316
+ volumetrics_metadata,
317
+ scene_database: scene.scene_database_buffer,
318
+ cascade_field,
319
+ },
320
+ group_count_x: Math.max(1, Math.ceil(volume_count / VOLUMETRICS_SUN_SHADOW_CULL_LANES)),
321
+ });
322
+
323
+ shader_volumetrics_bin_sun_shadow_media.dispatch({
324
+ encoder,
325
+ bindings: {
326
+ settings: bin_settings,
327
+ volumetrics_metadata,
328
+ scene_database: scene.scene_database_buffer,
329
+ cascade_field,
330
+ group_lists,
331
+ },
332
+ group_count_x: groups[0],
333
+ group_count_y: groups[1],
334
+ group_count_z: seeded ? interior_bricks_z : groups[2],
335
+ });
336
+
337
+ const bindings = {
338
+ settings: {
339
+ cascade,
340
+ sub_steps: volumetrics_sun_shadow_sub_steps(cascade),
341
+ },
342
+ volumetrics_metadata,
343
+ scene_database: scene.scene_database_buffer,
344
+ group_lists,
345
+ tParticipatingMediaNoise: noise_atlas.obtainView(),
346
+ sParticipatingMediaNoise: context.graphics.samplers.obtain(PARTICIPATING_MEDIA_NOISE_SAMPLER_DESCRIPTOR),
347
+ tSunShadowVolume: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
348
+ };
349
+
350
+ if (seeded) {
351
+ const outer = resources.get(data.outer);
352
+ bindings.sLinear = context.graphics.samplers.obtain(SAMPLER_LINEAR_UPSCALE);
353
+ bindings.tSunShadowOuter = outer.obtainView();
354
+ }
355
+
356
+ scene.wind.bind(bindings);
357
+
358
+ const switches = shader_switches.with(WIND_FIELD_UNIFORM, scene.wind.cascade_count === 0);
359
+
360
+ base_shader.variant(switches).dispatch({
361
+ encoder,
362
+ bindings,
363
+ group_count_x: group_count[0],
364
+ group_count_y: group_count[1],
365
+ group_count_z: group_count[2],
366
+ });
367
+ }
368
+ );
369
+
370
+ data.volumetrics_metadata = pass.read(volumetrics_metadata);
371
+ data.noise_atlas = pass.read(noise_atlas);
372
+
373
+ if (seeded) {
374
+ data.outer = pass.read(cascades[cascade + 1]);
375
+ }
376
+
377
+ data.cascade_field = pass.create(`sun shadow cascade ${cascade} field`, BufferResourceDescriptor.from(
378
+ field_bytes,
379
+ GPUBufferUsage.STORAGE,
380
+ 0, 4,
381
+ ));
382
+ data.group_lists = pass.create(`sun shadow cascade ${cascade} group lists`, BufferResourceDescriptor.from(
383
+ group_lists_bytes,
384
+ GPUBufferUsage.STORAGE,
385
+ 0, group_lists_bytes,
386
+ ));
387
+ data.output = pass.create(`Sun Shadow Cascade ${cascade}`, TextureResourceDescriptor.from({
388
+ resolution,
389
+ dimension: "3d",
390
+ format: "rgba16float",
391
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
392
+ }));
393
+
394
+ cascades[cascade] = data.output;
395
+ }
396
+
397
+ return cascades;
398
+ }
399
+
400
+ /**
401
+ *
402
+ * @param {FrameGraph} graph
403
+ * @param participating_media0
404
+ * @param participating_media1
405
+ * @param volumetrics_metadata
406
+ * @param light_cluster_data
407
+ * @param light_cluster_lookup
408
+ * @param light_cluster_parameters
409
+ * @param shadowmap_atlas
410
+ * @param sun_transmittance_lut
411
+ * @param sun_multiple_scattering_lut
412
+ * @param {number[]} sun_shadow_cascades handles of the Q-04 optical-depth cascades, innermost first
413
+ * @param lights
414
+ * @param view
415
+ * @param camera
416
+ * @param resolution
417
+ * @param {ShaderSwitchSet} shader_switches the renderer's; the lighting pass is built for them
418
+ * @returns {number} the lit scattering volume
419
+ */
420
+ function graph_integrate_light_scattering({
421
+ graph,
422
+ participating_media0,
423
+ participating_media1,
424
+ volumetrics_metadata,
425
+ light_cluster_data,
426
+ light_cluster_lookup,
427
+ light_cluster_parameters,
428
+ shadowmap_atlas,
429
+ sun_transmittance_lut,
430
+ sun_multiple_scattering_lut,
431
+ sun_shadow_cascades,
432
+ sky,
433
+ lights,
434
+ view,
435
+ camera,
436
+ resolution,
437
+ shader_switches,
438
+ }) {
439
+
440
+ const data = {};
441
+
442
+ const pass = graph.add("scattering lut", data, (data, resources, context) => {
443
+ const output = resources.get(data.output);
444
+
445
+ const volumetrics_metadata = resources.get(data.volumetrics_metadata);
446
+
447
+ const participating_media0 = resources.get(data.participating_media0);
448
+ const participating_media1 = resources.get(data.participating_media1);
449
+
450
+ const light_cluster_data = resources.get(data.light_cluster_data);
451
+ const light_cluster_lookup = resources.get(data.light_cluster_lookup);
452
+ const light_cluster_parameters = resources.get(data.light_cluster_parameters);
453
+ const shadowmap_atlas = resources.get(data.shadowmap_atlas);
454
+
455
+ const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
456
+ const sun_multiple_scattering_lut = resources.get(data.sun_multiple_scattering_lut);
457
+ const sun_shadow_cascades = data.sun_shadow_cascades.map(handle => resources.get(handle));
458
+
459
+ const sampler_shadowmap = context.graphics.samplers.obtain(SHADOWMAP_COMPARE_SAMPLER_DESCRIPTOR);
460
+ const sLinear = context.graphics.samplers.obtain(SamplerDescriptor.from({
461
+ magFilter: "linear",
462
+ }));
463
+
464
+ // Spatiotemporal blue noise for the per-froxel sample offset. The pass takes one sample and
465
+ // leans on the volumetric TAA to integrate, which only works if each froxel's sequence over
466
+ // frames is well distributed — the property a per-froxel hash does not have.
467
+ const tSTBN_vec3 = context.graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
468
+
469
+ const encoder = context.encoder;
470
+
471
+ const bindings = {
472
+ camera: camera.buffer.buffer,
473
+ view: view.uniform_buffer.buffer,
474
+ volumetrics_metadata,
475
+ atmosphere: sky.parameters_buffer.buffer,
476
+ sLinear,
477
+ tSunTransmittance: sun_transmittance_lut.obtainView(),
478
+ tMultiScattering: sun_multiple_scattering_lut.obtainView(),
479
+ tSTBN_vec3: tSTBN_vec3.obtainView(),
480
+ tParticipatingMedia0: participating_media0.obtainView(),
481
+ tParticipatingMedia1: participating_media1.obtainView(),
482
+ tLighting: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
483
+ //
484
+ light_data: lights.buffer_data,
485
+
486
+ cluster_data: light_cluster_data,
487
+ cluster_lookup: light_cluster_lookup,
488
+ cluster_parameters: light_cluster_parameters,
489
+
490
+ shadowmapAtlas: shadowmap_atlas.obtainView(),
491
+ sCompareLinear: sampler_shadowmap,
492
+ };
493
+
494
+ // One texture per cascade, under the names the read side declares. Bound here rather than
495
+ // above because the count is a constant of the structure, not of this pass.
496
+ for (let cascade = 0; cascade < sun_shadow_cascades.length; cascade++) {
497
+ bindings[volumetrics_sun_shadow_texture_name(cascade)] = sun_shadow_cascades[cascade].obtainView();
498
+ }
499
+
500
+ shader_volumetrics_build_lighting.variant(shader_switches).dispatchThreads({
501
+ encoder,
502
+ thread_count_x: output.width,
503
+ thread_count_y: output.height,
504
+ thread_count_z: output.depth,
505
+ bindings
506
+ })
507
+ });
508
+
509
+ data.participating_media0 = pass.read(participating_media0);
510
+ data.participating_media1 = pass.read(participating_media1);
511
+ data.volumetrics_metadata = pass.read(volumetrics_metadata);
512
+
513
+ data.shadowmap_atlas = pass.read(shadowmap_atlas);
514
+ data.light_cluster_data = pass.read(light_cluster_data);
515
+ data.light_cluster_lookup = pass.read(light_cluster_lookup);
516
+ data.light_cluster_parameters = pass.read(light_cluster_parameters);
517
+
518
+ data.sun_transmittance_lut = pass.read(sun_transmittance_lut);
519
+ data.sun_multiple_scattering_lut = pass.read(sun_multiple_scattering_lut);
520
+ data.sun_shadow_cascades = sun_shadow_cascades.map(handle => pass.read(handle));
521
+
522
+ data.output = pass.create("Light Scattering LUT", TextureResourceDescriptor.from({
523
+ resolution,
524
+ dimension: "3d",
525
+ format: "rgba16float",
526
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT
527
+ }));
528
+
529
+ return data.output;
530
+
531
+ }
532
+
533
+ /**
534
+ * The fog: participating media -> per-froxel lighting -> ray-marched integration into the aerial LUT
535
+ * every surface behind it is seen through. Particle lighting is not here — it needs no medium, and
536
+ * `GPUIrradianceClipmap` builds it on its own.
537
+ *
538
+ * @param {Object} options
539
+ * @param {FrameGraph} options.graph
540
+ * @param {GPUCameraContext} options.camera
541
+ * @param {GPULightCollection} options.lights
542
+ * @param {GPUViewContext} options.view
543
+ * @param {GPUSky} options.sky the scene's sky, already {@link GPUSky#update updated}: its two
544
+ * persistent LUTs are imported and read, not rebuilt. The sun's transmittance and the multiple
545
+ * scattering depend on nothing but the atmosphere's constants, so building them again per frame
546
+ * bought the same texels at a cost that was paid whether or not the scene had any fog.
547
+ * @param {number} options.light_cluster_data
548
+ * @param {number} options.light_cluster_lookup
549
+ * @param {number} options.light_cluster_parameters
550
+ * @param {number} options.shadowmap_atlas
551
+ * @param {number[]} options.volumetric_resolution
552
+ * @param {number[]} options.sun_shadow_resolution voxel counts of one Q-04 sun optical-depth cascade;
553
+ * `[1, 1, 1]` when the froxels are marching instead, which keeps the passes in the graph without
554
+ * doing any work
555
+ * @param {number} options.volumetrics_metadata
556
+ * @param {number} [options.taa_history] imported previous-frame accumulated scattering volume
557
+ * @param {number} [options.taa_output] imported destination for this frame's accumulated scattering volume
558
+ * @param {GPUCameraContext} [options.camera_previous] previous-frame camera, for temporal reprojection
559
+ * @param {ShaderSwitchSet} [options.shader_switches] the renderer's; the lighting pass is built for them
560
+ */
561
+ export function graph_build_volumetrics({
562
+ graph,
563
+ camera,
564
+ lights,
565
+ view,
566
+ sky,
567
+ light_cluster_data,
568
+ light_cluster_lookup,
569
+ light_cluster_parameters,
570
+ shadowmap_atlas,
571
+ volumetric_resolution,
572
+ sun_shadow_resolution,
573
+ volumetrics_metadata,
574
+ taa_history,
575
+ taa_output,
576
+ camera_previous,
577
+ shader_switches = ShaderSwitchSet.EMPTY,
578
+ }) {
579
+
580
+ assert.defined(view, 'view');
581
+ assert.defined(sky, 'sky');
582
+ assert.equal(sky.needs_update, false, 'sky has not been updated, its LUTs hold nothing yet');
583
+ assert.defined(volumetric_resolution, 'volumetric_resolution');
584
+ assert.defined(sun_shadow_resolution, 'sun_shadow_resolution');
585
+
586
+ graph.push_scope("build volumetrics");
587
+
588
+ // Read-only here, so nothing in this graph orders against a write to either; the sky wrote
589
+ // them in commands of its own, submitted before this frame's.
590
+ const transmittance_lut = graph_import_texture(graph, sky.lut_transmittance);
591
+ const multiscatted_lut = graph_import_texture(graph, sky.lut_multiple_scattering);
592
+
593
+ const {
594
+ participating_media0,
595
+ participating_media1,
596
+ far_field,
597
+ } = graph_integrate_participating_media({
598
+ graph,
599
+ scene: view.scene,
600
+ view,
601
+ resolution: volumetric_resolution,
602
+ volumetrics_metadata,
603
+ camera,
604
+ shader_switches,
605
+ });
606
+
607
+ const sun_shadow_cascades = graph_build_sun_shadow_volume({
608
+ graph,
609
+ scene: view.scene,
610
+ volumetrics_metadata,
611
+ resolution: sun_shadow_resolution,
612
+ shader_switches,
613
+ });
614
+
615
+ const light_scattering_lut = graph_integrate_light_scattering({
616
+ graph,
617
+ resolution: volumetric_resolution,
618
+ camera,
619
+ view,
620
+ sun_transmittance_lut: transmittance_lut,
621
+ sun_multiple_scattering_lut: multiscatted_lut,
622
+ sun_shadow_cascades,
623
+ sky,
624
+ participating_media0,
625
+ participating_media1,
626
+ volumetrics_metadata,
627
+ light_cluster_data,
628
+ light_cluster_lookup,
629
+ light_cluster_parameters,
630
+ shadowmap_atlas,
631
+ lights,
632
+ shader_switches,
633
+ });
634
+
635
+ // Temporal reprojection of the per-froxel lit scattering volume, applied BEFORE aerial
636
+ // integration — reprojecting the already-integrated aerial LUT would double-integrate along the
637
+ // view ray. Optional: skipped when no history ping-pong is supplied (TAA disabled), in which
638
+ // case the aerial pass consumes the raw (noisier) scattering LUT directly.
639
+ let volume_lighting_resolved = light_scattering_lut;
640
+
641
+ if (taa_history !== undefined && taa_output !== undefined) {
642
+ const taa_outputs = graph_compute_pass({
643
+ graph,
644
+ shader: shader_volumetrics_taa,
645
+ group_count: [
646
+ Math.ceil(volumetric_resolution[0] / 8),
647
+ Math.ceil(volumetric_resolution[1] / 8),
648
+ Math.ceil(volumetric_resolution[2] / 4),
649
+ ],
650
+ bindings: {
651
+ t_current: light_scattering_lut,
652
+ t_history: taa_history,
653
+ t_output: taa_output,
654
+ volumetrics_metadata,
655
+ camera_current: graph_import_buffer(graph, camera.buffer.buffer, "volumetrics taa camera"),
656
+ camera_previous: graph_import_buffer(graph, camera_previous.buffer.buffer, "volumetrics taa camera previous"),
657
+ },
658
+ });
659
+
660
+ volume_lighting_resolved = taa_outputs.t_output;
661
+ }
662
+
663
+ const a_data = {};
664
+
665
+ const a_pass = graph.add("aerial lut", a_data, (data, resources, context) => {
666
+ const output = resources.get(data.output);
667
+
668
+ const participating_media0 = resources.get(data.participating_media0);
669
+ const participating_media1 = resources.get(data.participating_media1);
670
+ const volumetrics_metadata = resources.get(data.volumetrics_metadata);
671
+
672
+ const light_scattering_lut = resources.get(data.light_scattering_lut);
673
+ const sun_transmittance_lut = resources.get(data.sun_transmittance_lut);
674
+ const far_field = resources.get(data.far_field);
675
+
676
+ const encoder = context.encoder;
677
+
678
+
679
+ const graphics = context.graphics;
680
+
681
+ const sLinear = graphics.samplers.obtain(SamplerDescriptor.from({
682
+ magFilter: "linear",
683
+ }));
684
+
685
+ const tSTBN_vec3 = graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3);
686
+
687
+ shader_volumetrics_build_scattering_lut.dispatchThreads({
688
+ encoder,
689
+ thread_count_x: output.width,
690
+ thread_count_y: output.height,
691
+ bindings: {
692
+ camera: camera.buffer.buffer,
693
+ view: view.uniform_buffer.buffer,
694
+ volumetrics_metadata,
695
+ tSTBN_vec3: tSTBN_vec3.obtainView(),
696
+ sLinear,
697
+
698
+ tVolumeLighting: light_scattering_lut.obtainView(),
699
+ tParticipatingMedia0: participating_media0.obtainView(),
700
+ tParticipatingMedia1: participating_media1.obtainView(),
701
+
702
+ // RDR2-style far-field march inputs (used beyond froxel_far)
703
+ scene_database: view.scene.scene_database_buffer,
704
+ far_field,
705
+ light_data: lights.buffer_data,
706
+ atmosphere: sky.parameters_buffer.buffer,
707
+ tSunTransmittance: sun_transmittance_lut.obtainView(),
708
+
709
+ tOutput: output.obtainView(DEFAULT_RENDER_TARGET_VIEW_DESCRIPTOR),
710
+ }
711
+ });
712
+
713
+
714
+ });
715
+
716
+ a_data.participating_media0 = a_pass.read(participating_media0);
717
+ a_data.participating_media1 = a_pass.read(participating_media1);
718
+ a_data.volumetrics_metadata = a_pass.read(volumetrics_metadata);
719
+ a_data.sun_transmittance_lut = a_pass.read(transmittance_lut);
720
+ a_data.far_field = a_pass.read(far_field);
721
+
722
+ a_data.output = a_pass.create("Integrated Volumetrics", TextureResourceDescriptor.from({
723
+ resolution: volumetric_resolution,
724
+ dimension: "3d",
725
+ format: "rgba16float",
726
+ usage: GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.TEXTURE_BINDING
727
+ }))
728
+
729
+
730
+ a_data.light_scattering_lut = a_pass.read(volume_lighting_resolved);
731
+
732
+
733
+ // TODO add temporal reprojection
734
+
735
+ graph.pop_scope();
736
+
737
+ return {
738
+ lut_transmittance: transmittance_lut,
739
+ lut_multiple_scattering: multiscatted_lut,
740
+ lut_aerial: a_data.output,
741
+ volumetrics_metadata,
742
+ };
743
+ }