@woosh/meep-engine 3.39.0 → 3.40.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.
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/engine/EngineHarness.d.ts.map +1 -1
- package/src/engine/EngineHarness.js +17 -4
- package/src/engine/asset/loaders/image/avif/threaded_image_encoder.js +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
- package/src/engine/graphics/ecs/water/Water.d.ts +14 -17
- package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/Water.js +100 -110
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +36 -38
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.d.ts +6 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_3_4.js +10 -0
- package/src/engine/graphics/ecs/water/WaterWaves.d.ts +3 -3
- package/src/engine/graphics/ecs/water/WaterWaves.js +46 -46
- package/src/engine/graphics/texture/sampler/sampler2d_to_avif.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/sampler2d_to_avif.js +8 -5
- package/src/engine/graphics3/WaterSystem.d.ts +21 -74
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem.js +174 -367
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/format/image/avif/api/convert_to_rgba.d.ts +2 -2
- package/src/format/image/avif/api/convert_to_rgba.d.ts.map +1 -1
- package/src/format/image/avif/api/convert_to_rgba.js +10 -9
- package/src/format/image/avif/api/decode_avif.d.ts +2 -2
- package/src/format/image/avif/api/decode_avif.d.ts.map +1 -1
- package/src/format/image/avif/api/decode_avif.js +1 -1
- package/src/shade/playground/ssr_reprojection/README.md +111 -103
- package/src/shade/playground/ssr_reprojection/SpatialFilterProbe.js +68 -68
- package/src/shade/playground/ssr_reprojection/index.html +80 -79
- package/src/shade/playground/ssr_reprojection/main.js +256 -247
- package/src/shade/playground/ssr_variance/capture.js +96 -96
- package/src/shade/playground/ssr_variance/reference.js +78 -78
- package/src/shade/playground/vsm/README.md +96 -0
- package/src/shade/playground/vsm/VSMDebugOverlay.d.ts +49 -0
- package/src/shade/playground/vsm/VSMDebugOverlay.d.ts.map +1 -0
- package/src/shade/playground/vsm/VSMDebugOverlay.js +351 -0
- package/src/shade/playground/vsm/clipmap_panel.d.ts +8 -0
- package/src/shade/playground/vsm/clipmap_panel.d.ts.map +1 -0
- package/src/shade/playground/vsm/clipmap_panel.js +138 -0
- package/src/shade/playground/vsm/index.html +170 -0
- package/src/shade/playground/vsm/main.d.ts +2 -0
- package/src/shade/playground/vsm/main.d.ts.map +1 -0
- package/src/shade/playground/vsm/main.js +389 -0
- package/src/shade/playground/vsm/scenes.d.ts +52 -0
- package/src/shade/playground/vsm/scenes.d.ts.map +1 -0
- package/src/shade/playground/vsm/scenes.js +320 -0
- package/src/shade/playground/vsm/verify_vsm.d.ts +38 -0
- package/src/shade/playground/vsm/verify_vsm.d.ts.map +1 -0
- package/src/shade/playground/vsm/verify_vsm.js +305 -0
- package/src/shade/playground/water_refraction/README.md +57 -9
- package/src/shade/playground/water_refraction/main.js +12 -3
- package/src/shade/playground/water_refraction/world.d.ts +1 -0
- package/src/shade/playground/water_refraction/world.d.ts.map +1 -1
- package/src/shade/playground/water_refraction/world.js +15 -5
- package/src/shade/renderer/Renderer.d.ts +19 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +72 -1
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts +8 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +18 -0
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts +7 -0
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +11 -0
- package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts +3 -1
- package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +10 -1
- package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_read_code.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_read_code.js +28 -0
- package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_write_code.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/serde/table_wgsl_gen_write_code.js +31 -1
- package/src/shade/renderer/geometry/MeshletGeometry.d.ts +3 -0
- package/src/shade/renderer/geometry/MeshletGeometry.d.ts.map +1 -1
- package/src/shade/renderer/geometry/MeshletGeometry.js +1 -0
- package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +62 -4
- package/src/shade/renderer/light/environment/rgbe/parse_rgbe.d.ts +1 -1
- package/src/shade/renderer/light/environment/rgbe/parse_rgbe.js +2 -2
- package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.d.ts +2 -2
- package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/rgbe_byte_to_rgb_half.js +6 -14
- package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/sh_exponential/chunk_sh_exp_workgroup_sum.js +5 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/medium/ParticipatingMedium.d.ts +3 -0
- package/src/shade/renderer/medium/ParticipatingMedium.d.ts.map +1 -1
- package/src/shade/renderer/medium/ParticipatingMedium.js +7 -0
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_build_histogram.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_build_histogram.js +5 -35
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts +12 -4
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/SSR.js +36 -8
- package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.d.ts +3 -0
- package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/SSR_DENOISE_TILE_SIZE.js +2 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.d.ts +8 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/chunk_ssr_denoise_tile_active.js +40 -0
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +150 -137
- package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.d.ts +3 -0
- package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_classify.js +44 -0
- package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.d.ts +5 -0
- package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/shader_ssr_denoise_tile_dilate.js +35 -0
- package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.d.ts +26 -0
- package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/ssr_graph_denoise_tiles.js +42 -0
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts +1 -0
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_reproject_shader.js +113 -105
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts +2 -0
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +177 -167
- package/src/shade/renderer/rasterize/DEPTH_STENCIL_STATE_SHADOW.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/DEPTH_STENCIL_STATE_SHADOW.js +10 -0
- package/src/shade/renderer/rasterize/RasterizationJob.d.ts +1 -2
- package/src/shade/renderer/rasterize/RasterizationJob.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/RasterizationJob.js +1 -2
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts +5 -6
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +5 -6
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +2 -2
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +1 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +11 -0
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/build_lut_fog_parameters_jendersie_deon.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/phase/jd/build_lut_fog_parameters_jendersie_deon.js +4 -5
- package/src/shade/renderer/shader/chunk/brdf/dfg/generate_dfg_texture.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/brdf/dfg/generate_dfg_texture.js +1 -5
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.d.ts +30 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_importance.js +54 -0
- package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +3 -2
- package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.d.ts +19 -0
- package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/DIRECTIONAL_SHADOWMAP_STRUCT.js +27 -0
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts +1 -0
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +4 -0
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts +54 -0
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +502 -10
- package/src/shade/renderer/shadow/map/Shadowmap.d.ts +3 -2
- package/src/shade/renderer/shadow/map/Shadowmap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/Shadowmap.js +3 -2
- package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.d.ts +8 -0
- package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_sample_shadowmap_atlas_for_light.js +34 -3
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts +3 -2
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.js +17 -2
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_point2.js +137 -133
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.d.ts +15 -0
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_FIRST_TEXEL_SIZE.js +14 -0
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.d.ts +16 -0
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/DEFAULT_VSM_PAGE_BUDGET.js +15 -0
- package/src/shade/renderer/shadow/vsm/PLAN.md +440 -0
- package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +43 -0
- package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts +42 -0
- package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSMMoverTracker.js +153 -0
- package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts +327 -0
- package/src/shade/renderer/shadow/vsm/VSMPageManager.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSMPageManager.js +1408 -0
- package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.d.ts +14 -0
- package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSM_COVER_LEVEL_STEP.js +13 -0
- package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.d.ts +63 -0
- package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSM_FEEDBACK_LAYOUT.js +70 -0
- package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.d.ts +11 -0
- package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSM_LEVEL_LIMIT.js +10 -0
- package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts +54 -0
- package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.js +75 -0
- package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.d.ts +23 -0
- package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSM_RECORD_STRUCT.js +85 -0
- package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.d.ts +16 -0
- package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/VSM_SLOT_STRUCT.js +29 -0
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts +136 -25
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +282 -116
- package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts +39 -0
- package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/graph_vsm_feedback.js +289 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.d.ts +18 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_virtual.js +65 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.d.ts +17 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_addressing.js +75 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts +14 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.js +45 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.d.ts +17 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_find_page.js +100 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.d.ts +15 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_page_view_projection.js +47 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.d.ts +26 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_demand.js +156 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.d.ts +13 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_gather_counts.js +65 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts +30 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.js +184 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts +23 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.js +109 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.d.ts +56 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/shader_vsm_stale.js +211 -0
- package/src/shade/renderer/texture/format/decode_typed_gpu_data.d.ts +1 -1
- package/src/shade/renderer/texture/format/decode_typed_gpu_data.d.ts.map +1 -1
- package/src/shade/renderer/texture/format/decode_typed_gpu_data.js +3 -13
- package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -1
- package/src/shade/renderer/texture/format/infer_format_from_parameters.js +2 -3
- package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
- package/src/shade/renderer/texture/texture_write_to_gpu.js +16 -16
- package/src/shade/renderer/texture/virtual/VTPhysicalCache.d.ts +4 -90
- package/src/shade/renderer/texture/virtual/VTPhysicalCache.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/VTPhysicalCache.js +6 -210
- package/src/shade/renderer/texture/virtual/VTPhysicalSlots.d.ts +119 -0
- package/src/shade/renderer/texture/virtual/VTPhysicalSlots.d.ts.map +1 -0
- package/src/shade/renderer/texture/virtual/VTPhysicalSlots.js +245 -0
- package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.d.ts +1 -1
- package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.js +3 -19
- package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.d.ts +13 -0
- package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.d.ts.map +1 -0
- package/src/shade/renderer/texture/virtual/chunk_vt_page_table_entry.js +34 -0
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +7 -2
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +49 -49
- package/src/shade/renderer/water/chunk_water_transport.js +3 -3
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +11 -25
- package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +1 -1
- package/src/shade/renderer/water/medium/GPUWaterBodies.js +64 -116
- package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts +1 -20
- package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/water/medium/WATER_BODIES_STRUCT.js +10 -42
- package/src/shade/renderer/water/medium/chunk_water_bodies.d.ts +3 -0
- package/src/shade/renderer/water/medium/chunk_water_bodies.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/chunk_water_bodies.js +3 -0
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts +1 -5
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.d.ts.map +1 -1
- package/src/shade/renderer/water/medium/shader_water_bodies_derive.js +32 -30
- package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts +4 -0
- package/src/shade/renderer/water/medium/shader_water_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/water/medium/shader_water_meshlets.js +69 -0
- package/src/shade/renderer/water/optics/chunk_water_inscatter.d.ts.map +1 -1
- package/src/shade/renderer/water/optics/chunk_water_inscatter.js +124 -123
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.d.ts.map +1 -1
- package/src/shade/renderer/water/optics/chunk_water_receiver_downwelling.js +75 -74
- package/src/shade/renderer/water/shader_water.d.ts +1 -1
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +490 -406
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts +12 -85
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/GPUWaterWaveSimulation.js +128 -408
- package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts +6 -0
- package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/WATER_WAVE_RECORD_STRUCT.js +23 -0
- package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts +9 -0
- package/src/shade/renderer/water/surface/chunk_water_tessellation.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/chunk_water_tessellation.js +144 -0
- package/src/shade/renderer/water/surface/chunk_water_wave.d.ts +3 -5
- package/src/shade/renderer/water/surface/chunk_water_wave.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/chunk_water_wave.js +40 -48
- package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +14 -0
- package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/graph_water_tessellation.js +34 -0
- package/src/shade/renderer/water/surface/shader_water_tiles.d.ts +4 -0
- package/src/shade/renderer/water/surface/shader_water_tiles.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_tiles.js +123 -0
- package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts +6 -0
- package/src/shade/renderer/water/surface/shader_water_wave_batch.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_wave_batch.js +85 -0
- package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts +6 -0
- package/src/shade/renderer/water/surface/shader_water_wave_domain.d.ts.map +1 -0
- package/src/shade/renderer/water/surface/shader_water_wave_domain.js +83 -0
- package/src/shade/renderer/water/water_height_texture_from_sampler.d.ts.map +1 -1
- package/src/shade/renderer/water/water_height_texture_from_sampler.js +4 -3
- package/src/engine/graphics/ecs/water/WATER_SIZE.d.ts +0 -2
- package/src/engine/graphics/ecs/water/WATER_SIZE.d.ts.map +0 -1
- package/src/engine/graphics/ecs/water/WATER_SIZE.js +0 -1
- package/src/shade/renderer/light/GPUViewLightContext.d.ts +0 -22
- package/src/shade/renderer/light/GPUViewLightContext.d.ts.map +0 -1
- package/src/shade/renderer/light/GPUViewLightContext.js +0 -62
- package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts +0 -14
- package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/shadow/map/csm/CSM_SHADOWMAP_STRUCT.js +0 -20
- package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts +0 -27
- package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/GPUViewShadowMaps.js +0 -147
- package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts +0 -7
- package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/GPUVirtualShadowTextureResidence.js +0 -10
- package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.d.ts +0 -2
- package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/VSM_RESIDENCE_WORKGROUP_TILE_RESOLUTION.js +0 -1
- package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts +0 -3
- package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/VSM_UNIFORMS_STRUCT.js +0 -8
- package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts +0 -27
- package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowmapRenderer.js +0 -102
- package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.d.ts +0 -8
- package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/debug_inspect_coarse_bounds_buffer.js +0 -34
- package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.d.ts +0 -10
- package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/debug_inspect_residence_buffer.js +0 -64
- package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts +0 -11
- package/src/shade/renderer/shadow/vsm/decode_tile_address.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/decode_tile_address.js +0 -26
- package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.d.ts +0 -2
- package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/render/vms_render_tiles.js +0 -11
- package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts +0 -20
- package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/vms_pipeline_compute_coarse_bounds.js +0 -184
- package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts +0 -25
- package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/vsm_residence_pipeline.js +0 -230
- package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts +0 -19
- package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.d.ts.map +0 -1
- package/src/shade/renderer/shadow/vsm/vsm_tile_allocation_pipeline.js +0 -127
- package/src/shade/renderer/texture/encode/ENCODE_NOTES_2026_09_02.md +0 -462
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts +0 -23
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance.d.ts.map +0 -1
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts +0 -18
- package/src/shade/renderer/water/optics/chunk_water_light_transmittance_dry.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts +0 -12
- package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/WATER_SURFACE_VERTEX_STRUCT.js +0 -27
- package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts +0 -14
- package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/WATER_WAVE_PARAMETERS_STRUCT.js +0 -49
- package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts +0 -9
- package/src/shade/renderer/water/surface/chunk_water_wave_grid.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/chunk_water_wave_grid.js +0 -47
- package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts +0 -10
- package/src/shade/renderer/water/surface/shader_water_surface_write.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/shader_water_surface_write.js +0 -51
- package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts +0 -12
- package/src/shade/renderer/water/surface/shader_water_wave_step.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/shader_water_wave_step.js +0 -54
- package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts +0 -13
- package/src/shade/renderer/water/surface/water_surface_grid_indices.d.ts.map +0 -1
- package/src/shade/renderer/water/surface/water_surface_grid_indices.js +0 -39
|
@@ -1,406 +1,490 @@
|
|
|
1
|
-
import { GPUShaderStage } from "../../descriptor/GPUShaderStage.js";
|
|
2
|
-
import { DepthStencilState } from "../../descriptor/pipeline/render/DepthStencilState.js";
|
|
3
|
-
import { RenderPipelineDescriptor } from "../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
|
|
4
|
-
import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
|
|
5
|
-
import { SHADING_LIGHT_RESOURCE_GROUP } from "../deferred/SHADING_LIGHT_RESOURCE_GROUP.js";
|
|
6
|
-
import { BRICK4_DATA_STRUCT } from "../global_illumination/brick4/gpu/BRICK4_DATA_STRUCT.js";
|
|
7
|
-
import { chunk_F_dielectric } from "../shader/chunk/brdf/fresnel/chunk_F_dielectric.js";
|
|
8
|
-
import { chunk_direction_view_to_world } from "../shader/chunk/camera/chunk_direction_view_to_world.js";
|
|
9
|
-
import { chunk_direction_world_to_view } from "../shader/chunk/camera/chunk_direction_world_to_view.js";
|
|
10
|
-
import { chunk_ray_at } from "../shader/chunk/geometry/ray/chunk_ray_at.js";
|
|
11
|
-
import { chunk_ffx_sssr_advance_ray } from "../shader/chunk/screen_space/chunk_ffx_sssr_advance_ray.js";
|
|
12
|
-
import { chunk_ffx_sssr_load_depth } from "../shader/chunk/screen_space/chunk_ffx_sssr_load_depth.js";
|
|
13
|
-
import { chunk_ffx_sssr_validate_hit } from "../shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js";
|
|
14
|
-
import { chunk_project_direction } from "../shader/chunk/screen_space/chunk_project_direction.js";
|
|
15
|
-
import { chunk_screen_space_newton_ray } from "../shader/chunk/screen_space/chunk_screen_space_newton_ray.js";
|
|
16
|
-
import { chunk_texture_sample_bilinear_uv } from "../shader/chunk/texture/sample/chunk_texture_sample_bilinear_uv.js";
|
|
17
|
-
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
18
|
-
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
19
|
-
import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
|
|
20
|
-
import { f32, u32 } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
21
|
-
import { WebGPUArray } from "../shader/type/WebGPUArray.js";
|
|
22
|
-
import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
|
|
23
|
-
import { VIEW_UNIFORM_STRUCT } from "../view/VIEW_UNIFORM_STRUCT.js";
|
|
24
|
-
import { chunk_water_gi_brick4, chunk_water_gi_ibl } from "./chunk_water_gi.js";
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
export const WATER_TRACE_STRUCT = WebGPUStruct.from({
|
|
43
|
-
max_distance: f32, distance_tolerance: f32, max_updates: u32, fallback_steps: u32,
|
|
44
|
-
mode: u32, reflections: u32,
|
|
45
|
-
// steps of the water body's in-scatter along each refracted view ray
|
|
46
|
-
inscatter_segments: u32,
|
|
47
|
-
}, "WaterTrace").pack();
|
|
48
|
-
|
|
49
|
-
function water_resources(finalize = false) {
|
|
50
|
-
const resources = new ShaderResourceSetDescriptor();
|
|
51
|
-
const group = resources.createGroup()
|
|
52
|
-
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
53
|
-
.addUniform("
|
|
54
|
-
.
|
|
55
|
-
.addTexture("
|
|
56
|
-
.addTexture("
|
|
57
|
-
.addTexture("
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
.addStorageBuffer(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/** Optics under
|
|
74
|
-
export const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
@
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
@
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
let
|
|
116
|
-
let
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
let
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
var
|
|
141
|
-
|
|
142
|
-
var
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let
|
|
150
|
-
let
|
|
151
|
-
let
|
|
152
|
-
let
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
var
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
let
|
|
295
|
-
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
let
|
|
308
|
-
|
|
309
|
-
let
|
|
310
|
-
let
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
let
|
|
333
|
-
var
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
let
|
|
373
|
-
let
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
1
|
+
import { GPUShaderStage } from "../../descriptor/GPUShaderStage.js";
|
|
2
|
+
import { DepthStencilState } from "../../descriptor/pipeline/render/DepthStencilState.js";
|
|
3
|
+
import { RenderPipelineDescriptor } from "../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
|
|
4
|
+
import { CAMERA_UNIFORM_STRUCT } from "../camera/CAMERA_UNIFORM_STRUCT.js";
|
|
5
|
+
import { SHADING_LIGHT_RESOURCE_GROUP } from "../deferred/SHADING_LIGHT_RESOURCE_GROUP.js";
|
|
6
|
+
import { BRICK4_DATA_STRUCT } from "../global_illumination/brick4/gpu/BRICK4_DATA_STRUCT.js";
|
|
7
|
+
import { chunk_F_dielectric } from "../shader/chunk/brdf/fresnel/chunk_F_dielectric.js";
|
|
8
|
+
import { chunk_direction_view_to_world } from "../shader/chunk/camera/chunk_direction_view_to_world.js";
|
|
9
|
+
import { chunk_direction_world_to_view } from "../shader/chunk/camera/chunk_direction_world_to_view.js";
|
|
10
|
+
import { chunk_ray_at } from "../shader/chunk/geometry/ray/chunk_ray_at.js";
|
|
11
|
+
import { chunk_ffx_sssr_advance_ray } from "../shader/chunk/screen_space/chunk_ffx_sssr_advance_ray.js";
|
|
12
|
+
import { chunk_ffx_sssr_load_depth } from "../shader/chunk/screen_space/chunk_ffx_sssr_load_depth.js";
|
|
13
|
+
import { chunk_ffx_sssr_validate_hit } from "../shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js";
|
|
14
|
+
import { chunk_project_direction } from "../shader/chunk/screen_space/chunk_project_direction.js";
|
|
15
|
+
import { chunk_screen_space_newton_ray } from "../shader/chunk/screen_space/chunk_screen_space_newton_ray.js";
|
|
16
|
+
import { chunk_texture_sample_bilinear_uv } from "../shader/chunk/texture/sample/chunk_texture_sample_bilinear_uv.js";
|
|
17
|
+
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
18
|
+
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
19
|
+
import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
|
|
20
|
+
import { f32, u32 } from "../shader/type/WEBGPU_WGSL_PRIMITIVE_TYPES.js";
|
|
21
|
+
import { WebGPUArray } from "../shader/type/WebGPUArray.js";
|
|
22
|
+
import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
|
|
23
|
+
import { VIEW_UNIFORM_STRUCT } from "../view/VIEW_UNIFORM_STRUCT.js";
|
|
24
|
+
import { chunk_water_gi_brick4, chunk_water_gi_ibl } from "./chunk_water_gi.js";
|
|
25
|
+
import { WATER_BODIES_TABLE, WATER_WAVES_TABLE } from "./medium/chunk_water_bodies.js";
|
|
26
|
+
import { MESHLET_METADATA_STRUCT } from "../geometry/meshlet/encoding/MESHLET_METADATA_STRUCT.js";
|
|
27
|
+
import { COLLECTION_U32_STRUCT_READ } from "../gpu_primitive/COLLECTION_U32_STRUCT_READ.js";
|
|
28
|
+
import { chunk_lower_bound_branchless } from "../shader/chunk/math/chunk_lower_bound_branchless.js";
|
|
29
|
+
import { chunk_water_tessellation, WATER_TILE_STRUCT, WATER_TESSELLATION_STRUCT, WATER_TILE_CELLS } from "./surface/chunk_water_tessellation.js";
|
|
30
|
+
import { chunk_read_meshlet_vertex_by_draw_index } from "../shader/chunk/geometry/meshlet/chunk_read_meshlet_vertex_by_draw_index.js";
|
|
31
|
+
import { chunk_scene_database_access } from "../scene/chunk_scene_database_access.js";
|
|
32
|
+
import { chunk_mat3_inverse } from "../shader/chunk/geometry/mat3/chunk_mat3_inverse.js";
|
|
33
|
+
import { NODE3D_GLOBAL_FLAG_MIRRORED } from "../scene/NODE3D_STRUCT.js";
|
|
34
|
+
import { chunk_water_inscatter } from "./optics/chunk_water_inscatter.js";
|
|
35
|
+
import { chunk_water_receiver_downwelling } from "./optics/chunk_water_receiver_downwelling.js";
|
|
36
|
+
import { chunk_water_optics } from "./optics/chunk_water_optics.js";
|
|
37
|
+
import { chunk_water_receiver_radiance, chunk_water_receiver_texel, chunk_water_refraction_confidence,
|
|
38
|
+
chunk_water_transport, WATER_LEVEL_TOLERANCE_DECLARATION } from './chunk_water_transport.js';
|
|
39
|
+
|
|
40
|
+
export const WATER_GRID_STRUCT = WebGPUStruct.from({ resolution: u32 }, 'WaterGrid');
|
|
41
|
+
|
|
42
|
+
export const WATER_TRACE_STRUCT = WebGPUStruct.from({
|
|
43
|
+
max_distance: f32, distance_tolerance: f32, max_updates: u32, fallback_steps: u32,
|
|
44
|
+
mode: u32, reflections: u32,
|
|
45
|
+
// steps of the water body's in-scatter along each refracted view ray
|
|
46
|
+
inscatter_segments: u32,
|
|
47
|
+
}, "WaterTrace").pack();
|
|
48
|
+
|
|
49
|
+
function water_resources(finalize = false) {
|
|
50
|
+
const resources = new ShaderResourceSetDescriptor();
|
|
51
|
+
const group = resources.createGroup()
|
|
52
|
+
.addUniform("camera", CAMERA_UNIFORM_STRUCT)
|
|
53
|
+
.addUniform("trace", WATER_TRACE_STRUCT)
|
|
54
|
+
.addTexture("tDepth")
|
|
55
|
+
.addTexture("tNormal", "uint")
|
|
56
|
+
.addTexture("tHZB")
|
|
57
|
+
.addTexture("tScene")
|
|
58
|
+
.addStorageBuffer('scene_database', WebGPUArray.u32)
|
|
59
|
+
.addStorageBuffer('water_tiles', WebGPUArray.from(WATER_TILE_STRUCT))
|
|
60
|
+
.addStorageBuffer('water_tile_sums', COLLECTION_U32_STRUCT_READ)
|
|
61
|
+
.addUniform('tessellation', WATER_TESSELLATION_STRUCT)
|
|
62
|
+
.addStorageBuffer('meshlet_metadata', WebGPUArray.from(MESHLET_METADATA_STRUCT))
|
|
63
|
+
.addStorageBuffer('meshlet_data', WebGPUArray.from(f32))
|
|
64
|
+
.addStorageBuffer('wave_state', WebGPUArray.from(f32))
|
|
65
|
+
.addUniform('wave_grid', WATER_GRID_STRUCT);
|
|
66
|
+
if (finalize) {
|
|
67
|
+
group.addTexture('receiver').addTexture('trace_metadata').addTexture('visibility_distance');
|
|
68
|
+
}
|
|
69
|
+
return resources;
|
|
70
|
+
}
|
|
71
|
+
const resources = water_resources();
|
|
72
|
+
|
|
73
|
+
/** Optics under IBL (and LPV, which has no transparent variant): the lights and the environment. */
|
|
74
|
+
export const WATER_FINALIZE_RESOURCES_IBL = water_resources(true);
|
|
75
|
+
WATER_FINALIZE_RESOURCES_IBL.addGroup(SHADING_LIGHT_RESOURCE_GROUP);
|
|
76
|
+
|
|
77
|
+
/** Optics under Brick4: the lights, and the light map with the view its sampling jitters by. */
|
|
78
|
+
export const WATER_FINALIZE_RESOURCES_BRICK4 = water_resources(true);
|
|
79
|
+
WATER_FINALIZE_RESOURCES_BRICK4.addGroup(SHADING_LIGHT_RESOURCE_GROUP);
|
|
80
|
+
WATER_FINALIZE_RESOURCES_BRICK4.createGroup()
|
|
81
|
+
.addStorageBuffer("brick4", BRICK4_DATA_STRUCT, false)
|
|
82
|
+
.addUniform("view", VIEW_UNIFORM_STRUCT);
|
|
83
|
+
|
|
84
|
+
const surface_body = CodeChunk.from(/* language=WGSL */ `
|
|
85
|
+
struct WaterVertexOut {
|
|
86
|
+
// Receivers and optics are separate modules drawing this mesh; optics tests depth 'equal'
|
|
87
|
+
// against the receivers' depth, and both must cover the same edge pixels. Only @invariant
|
|
88
|
+
// makes the position bit-identical across programs.
|
|
89
|
+
@invariant @builtin(position) clip: vec4<f32>,
|
|
90
|
+
@location(0) world: vec3<f32>,
|
|
91
|
+
@location(1) normal: vec3<f32>,
|
|
92
|
+
// slope variance of the waves the surface's mesh does not resolve
|
|
93
|
+
@location(2) unresolved_variance: f32,
|
|
94
|
+
@location(3) @interpolate(flat) body_index: u32,
|
|
95
|
+
@location(4) rest_normal: vec3<f32>,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fn water_wave_height(row: u32, cell: vec2i) -> f32 {
|
|
99
|
+
let n = i32(wave_grid.resolution);
|
|
100
|
+
let c = clamp(cell, vec2i(0), vec2i(n - 1));
|
|
101
|
+
return wave_state[row * u32(n * n) + u32(c.y * n + c.x)];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// One instance per occupied view tile and source triangle. All overlap candidates survive
|
|
105
|
+
// classification; receiver depth selects the nearest displaced interface.
|
|
106
|
+
@vertex
|
|
107
|
+
fn vs_main(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> WaterVertexOut {
|
|
108
|
+
let row = lower_bound_branchless(&water_tile_sums.elements, ii + 1u, water_tile_sums.count);
|
|
109
|
+
let definition = water_tiles[row];
|
|
110
|
+
let body = ${WATER_BODIES_TABLE.marshalling_method_read}(&scene_database, definition.body);
|
|
111
|
+
let header = meshlet_metadata[definition.meshlet];
|
|
112
|
+
let node = scene_read_node(&scene_database, body.node);
|
|
113
|
+
var previous = 0u;
|
|
114
|
+
if (row > 0u) { previous = water_tile_sums.elements[row - 1u]; }
|
|
115
|
+
let patch_index = ii - previous;
|
|
116
|
+
let tile = definition.origin + vec2i(i32(patch_index % definition.size.x), i32(patch_index / definition.size.x));
|
|
117
|
+
let cell = vi / 18u;
|
|
118
|
+
let lattice = tile * ${WATER_TILE_CELLS} + vec2i(i32(cell % ${WATER_TILE_CELLS}u), i32(cell / ${WATER_TILE_CELLS}u));
|
|
119
|
+
let pixel = vec2f(lattice) * definition.pixels;
|
|
120
|
+
let ndc0 = pixel / tessellation.resolution * vec2f(2,-2) + vec2f(-1,1);
|
|
121
|
+
// Form both endpoints from their integer lattice coordinate. Adding the pitch to
|
|
122
|
+
// an already rounded pixel coordinate gives neighbouring cells different edges.
|
|
123
|
+
let ndc1 = (vec2f(lattice + vec2i(1)) * definition.pixels) / tessellation.resolution * vec2f(2,-2) + vec2f(-1,1);
|
|
124
|
+
let a = read_meshlet_vertex_by_draw_index(header, definition.triangle * 3u);
|
|
125
|
+
let b = read_meshlet_vertex_by_draw_index(header, definition.triangle * 3u + 1u);
|
|
126
|
+
let c = read_meshlet_vertex_by_draw_index(header, definition.triangle * 3u + 2u);
|
|
127
|
+
let simulated = body.wave != ~0u;
|
|
128
|
+
let ca = tessellation.view_projection_matrix * (node.global * vec4f(water_reference_position(a.position, definition.anchor, simulated), 1));
|
|
129
|
+
let cb = tessellation.view_projection_matrix * (node.global * vec4f(water_reference_position(b.position, definition.anchor, simulated), 1));
|
|
130
|
+
let cc = tessellation.view_projection_matrix * (node.global * vec4f(water_reference_position(c.position, definition.anchor, simulated), 1));
|
|
131
|
+
let polygon = water_cell_polygon(ca, cb, cc, min(ndc0,ndc1), max(ndc0,ndc1));
|
|
132
|
+
let fan = (vi % 18u) / 3u;
|
|
133
|
+
if (polygon.count < fan + 3u) { return WaterVertexOut(vec4f(0,0,0,1),vec3f(0),vec3f(0,1,0),0,definition.body,vec3f(0,1,0)); }
|
|
134
|
+
let corner = select(vi % 3u, 2u - vi % 3u, (node.global_flags & ${NODE3D_GLOBAL_FLAG_MIRRORED}u) != 0u);
|
|
135
|
+
var index = 0u;
|
|
136
|
+
if (corner != 0u) { index = fan + corner; }
|
|
137
|
+
let barycentric = polygon.points[index];
|
|
138
|
+
var position = water_corner_position(a.position,b.position,c.position,ca,cb,cc,barycentric,
|
|
139
|
+
polygon.boundaries[index],min(ndc0,ndc1),max(ndc0,ndc1));
|
|
140
|
+
var normal = normalize(a.normal * barycentric.x + b.normal * barycentric.y + c.normal * barycentric.z);
|
|
141
|
+
let rest_normal = normal;
|
|
142
|
+
var variance = 0.0;
|
|
143
|
+
if (body.wave != ~0u) {
|
|
144
|
+
let params = ${WATER_WAVES_TABLE.marshalling_method_read}(&scene_database, body.wave);
|
|
145
|
+
let spacing = max((params.extent.zw - params.extent.xy) / f32(wave_grid.resolution - 1u), vec2f(1e-20));
|
|
146
|
+
let grid = clamp((position.xz - params.extent.xy) / spacing, vec2f(0.0), vec2f(f32(wave_grid.resolution - 1u)));
|
|
147
|
+
let cell = vec2i(grid);
|
|
148
|
+
let blend = fract(grid);
|
|
149
|
+
let h00 = water_wave_height(body.wave, cell);
|
|
150
|
+
let h10 = water_wave_height(body.wave, cell + vec2i(1, 0));
|
|
151
|
+
let h01 = water_wave_height(body.wave, cell + vec2i(0, 1));
|
|
152
|
+
let h11 = water_wave_height(body.wave, cell + vec2i(1, 1));
|
|
153
|
+
position.y += mix(mix(h00, h10, blend.x), mix(h01, h11, blend.x), blend.y);
|
|
154
|
+
let slope = vec2f(mix(h10 - h00, h11 - h01, blend.y), mix(h01 - h00, h11 - h10, blend.x)) / spacing;
|
|
155
|
+
normal = normalize(vec3f(normal.x - normal.y * slope.x, normal.y, normal.z - normal.y * slope.y));
|
|
156
|
+
variance = params.unresolved_variance;
|
|
157
|
+
}
|
|
158
|
+
let world = (node.global * vec4f(position, 1.0)).xyz;
|
|
159
|
+
let linear = mat3x3f(node.global[0].xyz, node.global[1].xyz, node.global[2].xyz);
|
|
160
|
+
let inverse_transpose = transpose(mat3_inverse(linear));
|
|
161
|
+
let normal_ws = normalize(inverse_transpose * normal);
|
|
162
|
+
let rest_normal_ws = normalize(inverse_transpose * rest_normal);
|
|
163
|
+
return WaterVertexOut(camera.view_projection_matrix * vec4f(world, 1.0), world, normal_ws, variance, definition.body,rest_normal_ws);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// The interface at one water fragment, in view space. Receivers trace through it and optics
|
|
167
|
+
// shade it, so both passes take it from here.
|
|
168
|
+
struct WaterInterface {
|
|
169
|
+
origin: vec3<f32>,
|
|
170
|
+
incident: vec3<f32>,
|
|
171
|
+
// Faces the camera's side of the interface.
|
|
172
|
+
normal: vec3<f32>,
|
|
173
|
+
ior: f32,
|
|
174
|
+
// Screen-space travel bound.
|
|
175
|
+
limit: f32,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
fn water_interface(world: vec3<f32>, surface_normal: vec3<f32>, ior: f32, above: bool) -> WaterInterface {
|
|
179
|
+
let origin = (camera.view_matrix * vec4f(world, 1.0)).xyz;
|
|
180
|
+
let view = normalize(camera.view_matrix_inverse[3].xyz - world);
|
|
181
|
+
let shading = normalize(select(-surface_normal, surface_normal, above));
|
|
182
|
+
// At a crest the interpolated shading normal can leave the rasterized face's
|
|
183
|
+
// visible hemisphere. Keep Snell/Fresnel on that face's side, continuously at grazing.
|
|
184
|
+
let normal_ws = normalize(shading + view * max(1e-4 - dot(shading,view), 0.0));
|
|
185
|
+
return WaterInterface(origin, normalize(origin), normalize(direction_world_to_view(normal_ws, camera)),
|
|
186
|
+
max(ior, 1.0), min(max(trace.max_distance, 0.1), camera.clip_near_far.y));
|
|
187
|
+
}
|
|
188
|
+
`, [chunk_direction_world_to_view, WATER_BODIES_TABLE.chunk_read, WATER_WAVES_TABLE.chunk_read,
|
|
189
|
+
chunk_read_meshlet_vertex_by_draw_index, chunk_scene_database_access, chunk_mat3_inverse,
|
|
190
|
+
chunk_lower_bound_branchless, chunk_water_tessellation]);
|
|
191
|
+
|
|
192
|
+
export const chunk_water_screen_ray = CodeChunk.from(/* language=WGSL */ `
|
|
193
|
+
fn water_hzb_mip_size(depth_size: vec2f, hzb_size: vec2f, mip: i32) -> vec2f {
|
|
194
|
+
if (mip <= 0) { return depth_size; }
|
|
195
|
+
return max(vec2f(1.0), floor(hzb_size / exp2(f32(mip-1))));
|
|
196
|
+
}
|
|
197
|
+
// Reuse the renderer's FFX cell intersection and depth loads, but walk the actual
|
|
198
|
+
// integer mip grids. Its SSR driver halves floating sizes and assumes power-of-two
|
|
199
|
+
// reductions; Meep's HZB conservatively resamples arbitrary viewport dimensions.
|
|
200
|
+
fn water_hzb_crossing(origin: vec3f, direction: vec3f, budget: u32,
|
|
201
|
+
valid: ptr<function,bool>, iterations: ptr<function,u32>) -> vec3f {
|
|
202
|
+
let size = vec2f(textureDimensions(tDepth,0));
|
|
203
|
+
let pyramid_size = vec2f(textureDimensions(tHZB,0));
|
|
204
|
+
let last_mip = i32(textureNumLevels(tHZB));
|
|
205
|
+
let inverse_direction = select(vec3f(F32_MAX), 1.0/direction, abs(direction)>vec3f(1e-12));
|
|
206
|
+
let floor_offset = select(vec2f(1.0), vec2f(0.0), direction.xy<vec2f(0.0));
|
|
207
|
+
let uv_offset = select(0.005/size, -0.005/size, direction.xy<vec2f(0.0));
|
|
208
|
+
var mip = 0;
|
|
209
|
+
var position = origin;
|
|
210
|
+
var travel = 0.0;
|
|
211
|
+
*valid = false;
|
|
212
|
+
// Water is absent from the opaque depth buffer: skipping the initial pixel
|
|
213
|
+
// can skip the entire receiver for almost zero projected displacement.
|
|
214
|
+
for (var i=0u; i<min(budget,128u); i++) {
|
|
215
|
+
*iterations = i+1u;
|
|
216
|
+
if (!screen_space_ray_in_bounds(position.xy) || is_background(position.z)) { break; }
|
|
217
|
+
let resolution = water_hzb_mip_size(size,pyramid_size,mip);
|
|
218
|
+
let pixel = resolution * position.xy;
|
|
219
|
+
let depth = ffx_sssr_load_depth(vec2i(pixel),mip);
|
|
220
|
+
let skipped = ffx_sssr_advance_ray(origin,direction,inverse_direction,pixel,
|
|
221
|
+
1.0/resolution,floor_offset,uv_offset,depth,&position,&travel);
|
|
222
|
+
if (!skipped && mip==0) { *valid=true; break; }
|
|
223
|
+
mip = clamp(mip+select(-1,1,skipped),0,last_mip);
|
|
224
|
+
}
|
|
225
|
+
return position;
|
|
226
|
+
}
|
|
227
|
+
// HZB returns a depth-slab crossing, not the intersection of the ray with the
|
|
228
|
+
// receiver's plane. Refine that crossing before using its UV or optical path.
|
|
229
|
+
fn water_exact_receiver(ray: Ray, input: ScreenSpaceRayHit) -> ScreenSpaceRayHit {
|
|
230
|
+
var hit = input;
|
|
231
|
+
if (hit.status != 0u) { return hit; }
|
|
232
|
+
let receiver = screen_space_ray_load_receiver(hit.uv, tDepth, tNormal,
|
|
233
|
+
camera.projection_matrix_inverse, camera.view_matrix);
|
|
234
|
+
let travel = plane_ray_raycast(ray.origin, ray.direction, receiver.plane);
|
|
235
|
+
// Keep the analytic distance rather than the projection of the texel center onto the ray.
|
|
236
|
+
if (travel > 1e-4 && travel <= ray.tmax) {
|
|
237
|
+
hit.distance = travel;
|
|
238
|
+
hit.uv = project_position(ray_at(ray.origin, ray.direction, travel), camera.projection_matrix).xy;
|
|
239
|
+
// Reprojection can change texel ownership at a silhouette. Validate that lookup
|
|
240
|
+
// again; the analytic travel above already checked the ray's bounded interval.
|
|
241
|
+
let checked = screen_space_ray_validate(Ray(ray.origin,ray.direction,1e20),hit.uv,tDepth,tNormal,
|
|
242
|
+
camera.projection_matrix,camera.projection_matrix_inverse,camera.view_matrix,trace.distance_tolerance);
|
|
243
|
+
hit.status = checked.status;
|
|
244
|
+
hit.residual = checked.residual;
|
|
245
|
+
} else { hit.status = 4u; }
|
|
246
|
+
return hit;
|
|
247
|
+
}
|
|
248
|
+
fn water_refine_receiver(ray: Ray, seed: vec2f) -> ScreenSpaceRayHit {
|
|
249
|
+
// The traversal already selected the first depth footprint. Intersect its plane
|
|
250
|
+
// once and validate ownership; another Newton search could jump past that footprint
|
|
251
|
+
// to a later root that the traversal has already ruled out.
|
|
252
|
+
return water_exact_receiver(ray, ScreenSpaceRayHit(seed, 0.0, 1e20, 0u, 0u));
|
|
253
|
+
}
|
|
254
|
+
fn water_hzb_hit(ray: Ray, budget: u32) -> ScreenSpaceRayHit {
|
|
255
|
+
var miss = ScreenSpaceRayHit(vec2f(0.0), 0.0, 1e20, 0u, 5u);
|
|
256
|
+
if (budget == 0u || !screen_space_ray_projectable(ray.origin, camera.projection_matrix)
|
|
257
|
+
|| !screen_space_ray_projectable(ray.origin + ray.direction, camera.projection_matrix)) { return miss; }
|
|
258
|
+
let origin = project_position(ray.origin, camera.projection_matrix);
|
|
259
|
+
let direction = project_direction(ray.origin, ray.direction, origin, camera.projection_matrix);
|
|
260
|
+
// Only rays advancing into reverse-Z are supported by this adapter.
|
|
261
|
+
if (direction.z >= -1e-8 || !screen_space_ray_in_bounds(origin.xy)) { return miss; }
|
|
262
|
+
var valid = false;
|
|
263
|
+
var iterations = 0u;
|
|
264
|
+
let candidate = water_hzb_crossing(origin, direction, budget, &valid, &iterations);
|
|
265
|
+
if (!valid) { miss.iterations = iterations; return miss; }
|
|
266
|
+
var hit = water_refine_receiver(ray, candidate.xy);
|
|
267
|
+
hit.iterations = iterations;
|
|
268
|
+
return hit;
|
|
269
|
+
}
|
|
270
|
+
`, [chunk_screen_space_newton_ray, chunk_ffx_sssr_advance_ray, chunk_ffx_sssr_load_depth, chunk_project_direction,
|
|
271
|
+
chunk_ray_at]);
|
|
272
|
+
|
|
273
|
+
const body = CodeChunk.from(/* language=WGSL */ `
|
|
274
|
+
struct WaterReceiver {
|
|
275
|
+
@location(0) receiver: vec4<f32>,
|
|
276
|
+
@location(1) metadata: vec4<f32>,
|
|
277
|
+
// Receiver UV, bounded path, classified status + Newton updates / 32. Readback is opt-in.
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// A screen-space receiver must lie below the surface point the ray entered at: the refracted ray runs
|
|
281
|
+
// downward from it, so any point on the ray is lower, and one that is not is a root off the ray.
|
|
282
|
+
fn water_receiver_submerged(uv: vec2f, surface: vec3f, normal: vec3f) -> bool {
|
|
283
|
+
let receiver = water_receiver_texel(tDepth, tNormal, vec2i(uv * vec2f(textureDimensions(tDepth, 0))),
|
|
284
|
+
camera.projection_matrix_inverse, camera.view_matrix_inverse);
|
|
285
|
+
return dot(receiver.position - surface, normal) <= WATER_LEVEL_TOLERANCE;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
@fragment
|
|
289
|
+
fn fs_main(in: WaterVertexOut, @builtin(front_facing) above: bool) -> WaterReceiver {
|
|
290
|
+
let water = ${WATER_BODIES_TABLE.marshalling_method_read}(&scene_database, in.body_index);
|
|
291
|
+
let coord = vec2<i32>(in.clip.xy);
|
|
292
|
+
let dimensions = vec2f(textureDimensions(tDepth, 0));
|
|
293
|
+
let uv = in.clip.xy / dimensions;
|
|
294
|
+
let scene_depth = textureLoad(tDepth, coord, 0).r;
|
|
295
|
+
if (scene_depth >= in.clip.z) { discard; }
|
|
296
|
+
// the opaque scene behind this pixel, and how deep under the surface point it lies: shore water
|
|
297
|
+
// fades in over its first 10 cm, whatever is under it
|
|
298
|
+
var behind_vs = vec3f(0.0);
|
|
299
|
+
var water_depth = 1e20;
|
|
300
|
+
if (!is_background(scene_depth)) {
|
|
301
|
+
behind_vs = inv_project_position(vec3f(uv, scene_depth), camera.projection_matrix_inverse);
|
|
302
|
+
// Measure shore thickness relative to the authored surface. Wave crests
|
|
303
|
+
// becoming tangent to the view do not turn deep water into a shore fade.
|
|
304
|
+
// Both sides retain coverage; back faces use bounded below-interface transport.
|
|
305
|
+
water_depth = abs(dot(in.world - (camera.view_matrix_inverse * vec4f(behind_vs, 1.0)).xyz, normalize(in.rest_normal)));
|
|
306
|
+
}
|
|
307
|
+
let coverage = smoothstep(0.0, 0.1, water_depth);
|
|
308
|
+
let surface = water_interface(in.world, in.normal, water.ior, above);
|
|
309
|
+
let interface_normal = direction_view_to_world(surface.normal, camera);
|
|
310
|
+
let limit = surface.limit;
|
|
311
|
+
let direction = refract(surface.incident, surface.normal, 1.0 / surface.ior);
|
|
312
|
+
let ray = Ray(surface.origin, normalize(direction), limit);
|
|
313
|
+
var hit = ScreenSpaceRayHit(uv, limit, 1e20, 0u, 8u);
|
|
314
|
+
var newton_updates = 0u;
|
|
315
|
+
var newton_failure = 0u;
|
|
316
|
+
if (above && trace.mode == 0u) {
|
|
317
|
+
// Mayer et al. §2.2: a root within one pixel of the ray is accepted as is. Like the paper,
|
|
318
|
+
// this can converge past a thin occluder; traversal is only the fallback for failures.
|
|
319
|
+
hit = screen_space_newton_ray(ray, uv, tDepth, tNormal, camera.projection_matrix,
|
|
320
|
+
camera.projection_matrix_inverse, camera.view_matrix, trace.max_updates, trace.distance_tolerance);
|
|
321
|
+
newton_updates = hit.iterations;
|
|
322
|
+
newton_failure = hit.status;
|
|
323
|
+
}
|
|
324
|
+
// Reject foreground receivers before deciding whether traversal is needed.
|
|
325
|
+
if (hit.status == 0u && !water_receiver_submerged(hit.uv, in.world, interface_normal)) { hit.status = 5u; newton_failure = 5u; }
|
|
326
|
+
if (above && trace.mode != 2u && hit.status != 0u) {
|
|
327
|
+
let fallback = water_hzb_hit(ray, trace.fallback_steps);
|
|
328
|
+
if (fallback.status == 0u && water_receiver_submerged(fallback.uv, in.world, interface_normal)) { hit = fallback; hit.status = 6u; }
|
|
329
|
+
}
|
|
330
|
+
// Compute the control event for every pixel, independently of Newton/HZB success. With nothing
|
|
331
|
+
// behind the water on screen, integrate it to where it has taken all but a thousandth.
|
|
332
|
+
let clearest = min(min(water.extinction.x, water.extinction.y), water.extinction.z);
|
|
333
|
+
var control_path = min(log(1000.0) / max(clearest, 1e-30), limit);
|
|
334
|
+
var control_status = select(8u, 9u, !above);
|
|
335
|
+
if (!is_background(scene_depth)) {
|
|
336
|
+
if (water_depth >= -WATER_LEVEL_TOLERANCE || !above) {
|
|
337
|
+
control_path = min(distance(ray.origin, behind_vs), limit);
|
|
338
|
+
control_status = select(7u, 9u, !above);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (trace.mode == 2u || !above || (hit.status != 0u && hit.status != 6u)) {
|
|
342
|
+
// Never use an unvalidated Newton iterate as a color lookup.
|
|
343
|
+
hit.uv = uv;
|
|
344
|
+
// A missing screen receiver is missing visibility, not 300 metres of water.
|
|
345
|
+
hit.distance = control_path;
|
|
346
|
+
hit.status = control_status;
|
|
347
|
+
}
|
|
348
|
+
var status = hit.status;
|
|
349
|
+
if (status == 6u) { status = 8u + newton_failure; }
|
|
350
|
+
else if (status == 7u) { status = 16u + newton_failure; }
|
|
351
|
+
else if (status == 8u) { status = 24u + newton_failure; }
|
|
352
|
+
else if (status == 9u) { status = 31u; }
|
|
353
|
+
return WaterReceiver(vec4f(hit.uv, hit.distance, f32(status) + f32(newton_updates)/32.0),
|
|
354
|
+
vec4f(control_path, min(hit.residual, 65504.0), coverage, f32(in.body_index + 1u)));
|
|
355
|
+
}
|
|
356
|
+
`, [surface_body, chunk_water_screen_ray, chunk_direction_view_to_world,
|
|
357
|
+
chunk_water_receiver_texel, WATER_LEVEL_TOLERANCE_DECLARATION]);
|
|
358
|
+
|
|
359
|
+
const finalize_body = CodeChunk.from(/* language=WGSL */ `
|
|
360
|
+
struct WaterOptics {
|
|
361
|
+
@location(0) transmission: vec4f,
|
|
362
|
+
@location(1) radiance: vec4f,
|
|
363
|
+
@location(2) background: vec4f,
|
|
364
|
+
}
|
|
365
|
+
@fragment
|
|
366
|
+
fn fs_main(in: WaterVertexOut, @builtin(front_facing) above: bool) -> WaterOptics {
|
|
367
|
+
let water = ${WATER_BODIES_TABLE.marshalling_method_read}(&scene_database, in.body_index);
|
|
368
|
+
let coord = vec2i(in.clip.xy);
|
|
369
|
+
let metadata = textureLoad(trace_metadata, coord, 0);
|
|
370
|
+
// Equal-depth surfaces must retain the same deterministic owner as receiver selection.
|
|
371
|
+
if (metadata.w != f32(in.body_index + 1u)) { discard; }
|
|
372
|
+
let dimensions = vec2f(textureDimensions(tDepth, 0));
|
|
373
|
+
let uv = in.clip.xy / dimensions;
|
|
374
|
+
let receiver_data = textureLoad(receiver, coord, 0);
|
|
375
|
+
let surface = water_interface(in.world, in.normal, water.ior, above);
|
|
376
|
+
let interface_normal = direction_view_to_world(surface.normal, camera);
|
|
377
|
+
let body = water;
|
|
378
|
+
let origin = surface.origin;
|
|
379
|
+
let ior = surface.ior;
|
|
380
|
+
let limit = surface.limit;
|
|
381
|
+
let nov = clamp(dot(-surface.incident, surface.normal), 0.0, 1.0);
|
|
382
|
+
// exact dielectric Fresnel: water is most reflective at grazing angles, where Schlick's is not right
|
|
383
|
+
let fresnel = F_dielectric(nov, ior);
|
|
384
|
+
let reflection_direction = reflect(surface.incident, surface.normal);
|
|
385
|
+
// a reflection that misses on screen falls back to the GI mode, as SSR's resolve does
|
|
386
|
+
var reflection = water_gi_specular(in.world, direction_view_to_world(surface.normal, camera),
|
|
387
|
+
direction_view_to_world(-surface.incident, camera), clamp(sqrt(water.roughness * water.roughness + in.unresolved_variance), 0.0, 1.0));
|
|
388
|
+
if (trace.reflections != 0u && above) {
|
|
389
|
+
let reflected = water_hzb_hit(Ray(ray_at(origin, reflection_direction, 0.02), reflection_direction, limit),
|
|
390
|
+
trace.fallback_steps);
|
|
391
|
+
if (reflected.status == 0u) {
|
|
392
|
+
let reflected_point = ray_at(origin, reflection_direction, reflected.distance + 0.02);
|
|
393
|
+
let projected = project_position(reflected_point, camera.projection_matrix);
|
|
394
|
+
// Reflection uses the renderer's usual back-face, thickness, self-hit and
|
|
395
|
+
// vignette validation. Its two-pixel rule must not reject normal-incidence refraction.
|
|
396
|
+
let confidence = ffx_sssr_validate_hit(vec3f(reflected.uv, projected.z), uv,
|
|
397
|
+
reflection_direction, dimensions, max(trace.distance_tolerance, 0.02), 0.05);
|
|
398
|
+
let radiance = water_receiver_radiance(tScene, tDepth, tNormal, reflected.uv,
|
|
399
|
+
camera.projection_matrix_inverse, camera.view_matrix_inverse, in.world, interface_normal, false);
|
|
400
|
+
reflection = mix(reflection, radiance.rgb,
|
|
401
|
+
confidence * min(radiance.a * 2.0, 1.0) * smoothstep(0.05, 0.5, reflected.distance)
|
|
402
|
+
* smoothstep(1.0, 4.0, length((reflected.uv - uv) * dimensions)));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
let original = textureLoad(tScene, coord, 0);
|
|
406
|
+
let valid = receiver_data.w < 16.0 && above && trace.mode != 2u;
|
|
407
|
+
var confidence = select(0.0, water_refraction_confidence(receiver_data.xy, uv, dimensions,
|
|
408
|
+
texture_sample_bilinear_uv(visibility_distance, uv, 0u).r), valid);
|
|
409
|
+
// Mayer's fade selects one UV, rather than crossfading two images of the same edge.
|
|
410
|
+
let lookup = water_refraction_lookup(uv, receiver_data.xy, confidence);
|
|
411
|
+
// The surface height here stands for the one above the displaced receiver: they differ by the
|
|
412
|
+
// wave height across a few metres, against a tolerance the gather already allows.
|
|
413
|
+
let gathered = water_receiver_radiance(tScene, tDepth, tNormal, lookup,
|
|
414
|
+
camera.projection_matrix_inverse, camera.view_matrix_inverse, in.world, interface_normal, above);
|
|
415
|
+
var path = metadata.x;
|
|
416
|
+
var color = original.rgb;
|
|
417
|
+
// the receiver seen through the surface: refracted, or the pixel's own when there is none
|
|
418
|
+
var receiver_coord = coord;
|
|
419
|
+
if (confidence > 0.0 && gathered.a > 0.0) {
|
|
420
|
+
path = min(water_receiver_path(tDepth, tNormal, lookup, camera.projection_matrix_inverse,
|
|
421
|
+
camera.view_matrix, origin), limit);
|
|
422
|
+
color = gathered.rgb;
|
|
423
|
+
receiver_coord = vec2i(lookup * dimensions);
|
|
424
|
+
} else { confidence = 0.0; }
|
|
425
|
+
// The opaque scene was shaded dry: what reaches the receiver is what survives the water above it
|
|
426
|
+
// (WATER_OPTICS_PLAN_2026_10_02.md §4.3). Seen from under the surface, the receiver is above it.
|
|
427
|
+
let receiver_texel = water_receiver_texel(tDepth, tNormal, receiver_coord, camera.projection_matrix_inverse,
|
|
428
|
+
camera.view_matrix_inverse);
|
|
429
|
+
if (above && !is_background(receiver_texel.depth)) {
|
|
430
|
+
let camera_ws = camera.view_matrix_inverse[3].xyz;
|
|
431
|
+
let up = normalize(in.rest_normal);
|
|
432
|
+
color *= water_receiver_downwelling(body, receiver_texel.position, receiver_texel.normal, up,
|
|
433
|
+
max(dot(in.world - receiver_texel.position, up), 0.0), normalize(camera_ws - receiver_texel.position));
|
|
434
|
+
}
|
|
435
|
+
// Light in the water body (WATER_OPTICS_PLAN_2026_10_02.md §4.4): the receiver attenuated along
|
|
436
|
+
// the refracted path, and the sun and sky scattered back up it; both cross the surface by the
|
|
437
|
+
// n² law. A view from under the surface is outside this model: attenuation only.
|
|
438
|
+
let extinction = body.extinction.xyz;
|
|
439
|
+
var transmitted = exp(-extinction * max(path, 0.0));
|
|
440
|
+
var scattered = vec3f(0.0);
|
|
441
|
+
if (above) {
|
|
442
|
+
let exit = water_exit_factor(nov, ior);
|
|
443
|
+
let direction = normalize(direction_view_to_world(refract(surface.incident, surface.normal, 1.0 / ior), camera));
|
|
444
|
+
transmitted *= exit;
|
|
445
|
+
scattered = exit * water_inscatter(body, in.world, direction, normalize(in.rest_normal), max(path, 0.0), trace.inscatter_segments);
|
|
446
|
+
}
|
|
447
|
+
let event = water_event(transmitted, fresnel * reflection + scattered);
|
|
448
|
+
let optical = water_transport(event, original.rgb, color, metadata.z);
|
|
449
|
+
return WaterOptics(vec4f(optical.transmission, metadata.z), vec4f(optical.radiance, confidence),
|
|
450
|
+
vec4f(optical.background, original.a));
|
|
451
|
+
}
|
|
452
|
+
`, [surface_body, chunk_water_screen_ray, chunk_F_dielectric,
|
|
453
|
+
chunk_ffx_sssr_validate_hit, chunk_texture_sample_bilinear_uv,
|
|
454
|
+
chunk_direction_view_to_world, chunk_ray_at, chunk_water_optics, chunk_water_inscatter,
|
|
455
|
+
chunk_water_receiver_downwelling, chunk_water_receiver_texel,
|
|
456
|
+
chunk_water_transport, chunk_water_receiver_radiance, chunk_water_refraction_confidence]);
|
|
457
|
+
|
|
458
|
+
export const water_shader = ShaderDescriptor.from({ label: "Water / receivers", resources, body });
|
|
459
|
+
/** The optics pass under IBL, and under LPV, which has no transparent variant. */
|
|
460
|
+
export const water_finalize_shader_ibl = ShaderDescriptor.from({ label: 'Water / coherent optics IBL',
|
|
461
|
+
resources: WATER_FINALIZE_RESOURCES_IBL, body: CodeChunk.from('', [finalize_body, chunk_water_gi_ibl]) });
|
|
462
|
+
/** The optics pass under Brick4. */
|
|
463
|
+
export const water_finalize_shader_brick4 = ShaderDescriptor.from({ label: 'Water / coherent optics Brick4',
|
|
464
|
+
resources: WATER_FINALIZE_RESOURCES_BRICK4, body: CodeChunk.from('', [finalize_body, chunk_water_gi_brick4]) });
|
|
465
|
+
export const WATER_RESOURCES = resources;
|
|
466
|
+
|
|
467
|
+
/** Nearest-interface selection writes only water-owned depth and optics, never opaque G-buffer. */
|
|
468
|
+
function water_pipeline(shader, targets, finalize) {
|
|
469
|
+
const code = shader.source;
|
|
470
|
+
const layout = shader.resources.generatePipelineLayout(GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT);
|
|
471
|
+
// Tile reconstruction spends six storage slots. Lighting spends four in the fragment stage.
|
|
472
|
+
// Keep their visibility precise so the Brick4 variant fits the guaranteed stage budget.
|
|
473
|
+
const vertex_only = new Set(['water_tiles', 'water_tile_sums', 'tessellation', 'meshlet_metadata', 'meshlet_data', 'wave_state', 'wave_grid']);
|
|
474
|
+
shader.resources.groups.forEach((group, gi) => group.resources.forEach((resource, ri) => {
|
|
475
|
+
layout.bindGroupLayouts[gi].entries[ri].visibility = vertex_only.has(resource.name) ? GPUShaderStage.VERTEX
|
|
476
|
+
: resource.name === 'camera' || resource.name === 'scene_database' ? GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT
|
|
477
|
+
: GPUShaderStage.FRAGMENT;
|
|
478
|
+
}));
|
|
479
|
+
return RenderPipelineDescriptor.from({
|
|
480
|
+
label: shader.label,
|
|
481
|
+
layout,
|
|
482
|
+
vertex: { module: { code }, entryPoint: "vs_main" },
|
|
483
|
+
fragment: { module: { code }, entryPoint: "fs_main", targets: targets.map(format => ({ format })) },
|
|
484
|
+
depthStencil: DepthStencilState.from({ format: "depth32float", depthWriteEnabled: !finalize, depthCompare: finalize ? 'equal' : 'greater' }),
|
|
485
|
+
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
export function create_water_pipeline() { return water_pipeline(water_shader, ['rgba32float', 'rgba32float'], false); }
|
|
489
|
+
export function create_water_finalize_pipeline_ibl() { return water_pipeline(water_finalize_shader_ibl, ['rgba32float', 'rgba16float', 'rgba16float'], true); }
|
|
490
|
+
export function create_water_finalize_pipeline_brick4() { return water_pipeline(water_finalize_shader_brick4, ['rgba32float', 'rgba16float', 'rgba16float'], true); }
|