@woosh/meep-engine 3.36.0 → 3.38.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/package.json +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +2 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts +11 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.d.ts.map +1 -0
- package/src/engine/ecs/transform/TRANSFORM64_EVENT_PLACED.js +10 -0
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.d.ts.map +1 -1
- package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +16 -0
- package/src/engine/graphics/ecs/water/Water.d.ts +30 -0
- package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/Water.js +125 -104
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/water/WaterSerializationAdapter.js +13 -1
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts +6 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.d.ts.map +1 -0
- package/src/engine/graphics/ecs/water/WaterSerializationUpgrader_1_2.js +18 -0
- package/src/engine/graphics3/WaterSystem.d.ts +22 -6
- package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/WaterSystem.js +314 -293
- package/src/engine/input/devices/XRInputDevice.d.ts +51 -23
- package/src/engine/input/devices/XRInputDevice.d.ts.map +1 -1
- package/src/engine/input/devices/XRInputDevice.js +145 -52
- package/src/engine/input/devices/xr/XRGamepadMapping.d.ts +14 -0
- package/src/engine/input/devices/xr/XRGamepadMapping.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRGamepadMapping.js +9 -0
- package/src/engine/input/devices/xr/XRHandedness.d.ts +15 -0
- package/src/engine/input/devices/xr/XRHandedness.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRHandedness.js +10 -0
- package/src/engine/input/devices/xr/XRInputAction.d.ts +24 -11
- package/src/engine/input/devices/xr/XRInputAction.d.ts.map +1 -1
- package/src/engine/input/devices/xr/XRInputAction.js +55 -24
- package/src/engine/input/devices/xr/XRInputButton.d.ts +7 -9
- package/src/engine/input/devices/xr/XRInputButton.d.ts.map +1 -1
- package/src/engine/input/devices/xr/XRInputButton.js +18 -8
- package/src/engine/input/devices/xr/XRInputCoordinates.d.ts +11 -3
- package/src/engine/input/devices/xr/XRInputCoordinates.d.ts.map +1 -1
- package/src/engine/input/devices/xr/XRInputCoordinates.js +17 -3
- package/src/engine/input/devices/xr/XRInputHandle.d.ts +41 -11
- package/src/engine/input/devices/xr/XRInputHandle.d.ts.map +1 -1
- package/src/engine/input/devices/xr/XRInputHandle.js +129 -32
- package/src/engine/input/devices/xr/XRInputPose.d.ts +41 -5
- package/src/engine/input/devices/xr/XRInputPose.d.ts.map +1 -1
- package/src/engine/input/devices/xr/XRInputPose.js +57 -16
- package/src/engine/input/devices/xr/XRInputTypes.d.ts +18 -18
- package/src/engine/input/devices/xr/XRInputTypes.js +3 -3
- package/src/engine/input/devices/xr/XRTargetRayMode.d.ts +17 -0
- package/src/engine/input/devices/xr/XRTargetRayMode.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRTargetRayMode.js +12 -0
- package/src/engine/input/devices/xr/XRVisibilityState.d.ts +15 -0
- package/src/engine/input/devices/xr/XRVisibilityState.d.ts.map +1 -0
- package/src/engine/input/devices/xr/XRVisibilityState.js +10 -0
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts +3 -1
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +5 -1
- package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts +19 -5
- package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/XRInputDeviceAdapter.js +42 -9
- package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts +8 -2
- package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/device/XR_INPUT_DEVICE_IDS.js +19 -9
- package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts +10 -2
- package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/trigger/InputTriggerXRButton.js +12 -2
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +13 -14
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +137 -36
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts +30 -0
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/cloth_collider_bounds.js +33 -0
- package/src/engine/physics/cloth/ecs/ClothColliderFlags.js +2 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts +10 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothColliderSystem.js +36 -14
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +15 -2
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +17 -2
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +19 -6
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +18 -20
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +139 -89
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +32 -16
- package/src/shade/playground/water_refraction/README.md +149 -0
- package/src/shade/playground/water_refraction/index.html +42 -0
- package/src/shade/playground/water_refraction/main.d.ts +2 -0
- package/src/shade/playground/water_refraction/main.d.ts.map +1 -0
- package/src/shade/playground/water_refraction/main.js +201 -0
- package/src/shade/playground/water_refraction/world.d.ts +37 -0
- package/src/shade/playground/water_refraction/world.d.ts.map +1 -0
- package/src/shade/playground/water_refraction/world.js +137 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +4 -0
- package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts +2 -3
- package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
- package/src/shade/renderer/animation/chunk_pose_accumulator.js +14 -24
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/shader_meshlet_bounds_reduce.js +16 -15
- package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +1123 -1122
- package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +202 -201
- package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts +8 -0
- package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/chunk_roughness_to_mip_ratio.js +24 -0
- package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts +0 -6
- package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/chunk_sphere_probe_roughness_to_lod.js +2 -25
- package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts +2 -2
- package/src/shade/renderer/light/environment/shader_project_environment_sh.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/shader_project_environment_sh.js +50 -19
- package/src/shade/renderer/particles/DESIGN.md +1 -1
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts +1 -1
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.d.ts.map +1 -1
- package/src/shade/renderer/particles/bounds/chunk_particle_bounds.js +10 -9
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +17 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +7 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_renormalization.js +11 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_rgb_contribution.js +19 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +5 -3
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts +4 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_split_counts.js +8 -0
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +21 -2
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_resolve.js +4 -8
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.d.ts.map +1 -1
- package/src/shade/renderer/scene/shader_bvh_extract_instance_leaves.js +10 -8
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_add_f32_storage.js +25 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_max_f32_storage.js +28 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/atomic/chunk_atomic_min_f32_storage.js +28 -0
- package/src/shade/renderer/shader/chunk/geometry/plane/{plane_ray_raycast.d.ts → chunk_plane_ray_raycast.d.ts} +2 -2
- package/src/shade/renderer/shader/chunk/geometry/plane/chunk_plane_ray_raycast.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/plane/{plane_ray_raycast.js → chunk_plane_ray_raycast.js} +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts +4 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_newton_ray.js +101 -0
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +3 -3
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +62 -29
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +235 -147
- package/src/shade/renderer/water/chunk_water_transport.d.ts +5 -0
- package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -0
- package/src/shade/renderer/water/chunk_water_transport.js +94 -0
- package/src/shade/renderer/water/shader_water.d.ts +9 -26
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +384 -246
- package/src/shade/renderer/water/shader_water_avboit.d.ts +12 -0
- package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -0
- package/src/shade/renderer/water/shader_water_avboit.js +258 -0
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +13 -0
- package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts +0 -29
- package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.d.ts.map +0 -1
- package/src/shade/renderer/animation/skinning/bounds_refresh/chunk_aabb_atomic_f32.js +0 -59
- package/src/shade/renderer/shader/chunk/geometry/plane/plane_ray_raycast.d.ts.map +0 -1
|
@@ -1,167 +1,255 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { half_to_float_uint16 } from "../../../core/binary/half_to_float_uint16.js";
|
|
2
|
+
import { TextureResourceDescriptor } from "../../device/graph/TextureResourceDescriptor.js";
|
|
3
|
+
import { DEFAULT_DEPTH_TEXTURE_VIEW } from "../depth/DEFAULT_DEPTH_TEXTURE_VIEW.js";
|
|
4
|
+
import { graph_compute_pass } from "../shader/graph/compute/graph_compute_pass.js";
|
|
5
|
+
import { graph_image_pass } from "../shader/graph/graph_image_pass.js";
|
|
6
|
+
import { STATIC_GRAPHICS_ENGINE_ASSETS } from "../STATIC_GRAPHICS_ENGINE_ASSETS.js";
|
|
3
7
|
import { SAMPLER_LINEAR_UPSCALE } from "../texture/SAMPLER_LINEAR_UPSCALE.js";
|
|
4
|
-
import { create_water_pipeline, WATER_DRAW_STRUCT,
|
|
8
|
+
import { create_water_pipeline, create_water_finalize_pipeline, WATER_DRAW_STRUCT, WATER_TRACE_STRUCT,
|
|
9
|
+
WATER_RESOURCES, WATER_FINALIZE_RESOURCES } from "./shader_water.js";
|
|
10
|
+
import { shader_water_background_copy, shader_water_debug, shader_water_draw,
|
|
11
|
+
shader_water_occupancy, shader_water_splat, shader_water_confidence_seed,
|
|
12
|
+
shader_water_confidence_x, shader_water_confidence_y } from "./shader_water_avboit.js";
|
|
5
13
|
|
|
6
|
-
/**
|
|
7
|
-
* Vertices per surface. Two triangles, generated from the vertex index — the surface is a rectangle
|
|
8
|
-
* at a constant height, so there is nothing to upload.
|
|
9
|
-
*
|
|
10
|
-
* @type {number}
|
|
11
|
-
*/
|
|
12
|
-
const VERTICES_PER_SURFACE = 6;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Draws water surfaces over a lit frame.
|
|
16
|
-
*
|
|
17
|
-
* **Water is a transparent pass on top of opaque**, which is why it lives here rather than in the
|
|
18
|
-
* material system: it is not shaded, it does not write the G-buffer, and it needs the finished
|
|
19
|
-
* depth of everything behind it in order to know how much water the view is looking through.
|
|
20
|
-
*
|
|
21
|
-
* The pass reads scene depth and writes the frame's colour, so it belongs at
|
|
22
|
-
* {@link FramePhase.AfterLighting} — opaque surfaces lit and composited, transparency not yet run.
|
|
23
|
-
*/
|
|
14
|
+
/** Production water channel. Only AVBOIT's shared resolve composites its radiance. */
|
|
24
15
|
export class GPUWaterRenderer {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
#pipeline =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* @param {string} color_format the frame colour this draws over
|
|
37
|
-
* @returns {RenderPipelineDescriptor}
|
|
38
|
-
*/
|
|
39
|
-
#obtain_pipeline(color_format) {
|
|
40
|
-
if (this.#pipeline === null || this.#pipeline_color_format !== color_format) {
|
|
41
|
-
this.#pipeline = create_water_pipeline({ color_format });
|
|
42
|
-
this.#pipeline_color_format = color_format;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return this.#pipeline;
|
|
16
|
+
surfaces = [];
|
|
17
|
+
settings = { enabled: true, max_distance: 300, distance_tolerance: 0.15,
|
|
18
|
+
max_updates: 4, fallback_steps: 48, mode: 0, reflections: 1, debug_view: 0 };
|
|
19
|
+
#pipeline = create_water_pipeline();
|
|
20
|
+
#finalize_pipeline = create_water_finalize_pipeline();
|
|
21
|
+
#prepared = new WeakMap();
|
|
22
|
+
#inspection = new WeakMap();
|
|
23
|
+
#probe = null;
|
|
24
|
+
|
|
25
|
+
avboit_is_empty() {
|
|
26
|
+
return !this.settings.enabled || !this.surfaces.some(s => s.visible && s.height_texture !== null);
|
|
46
27
|
}
|
|
47
28
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const data = {};
|
|
65
|
-
|
|
66
|
-
const pass = graph.add('water', data, (data, resources, context) => {
|
|
67
|
-
this.#execute(data, resources, context, surfaces, camera);
|
|
29
|
+
/** Optional single-pixel readback on the next rendered water frame. No per-frame readback. */
|
|
30
|
+
request_probe(uv) {
|
|
31
|
+
if (this.avboit_is_empty()) { return Promise.reject(new Error("No active water to inspect")); }
|
|
32
|
+
if (this.#probe !== null) { return Promise.reject(new Error("Water probe already pending")); }
|
|
33
|
+
if (uv.length !== 2 || !Array.from(uv).every(Number.isFinite)) {
|
|
34
|
+
return Promise.reject(new Error("Water probe requires two finite UV coordinates"));
|
|
35
|
+
}
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const probe = { uv: Array.from(uv),
|
|
38
|
+
resolve: value => { clearTimeout(timeout); resolve(value); },
|
|
39
|
+
reject: error => { clearTimeout(timeout); reject(error); } };
|
|
40
|
+
const timeout = setTimeout(() => {
|
|
41
|
+
if (this.#probe === probe) { this.#probe = null; }
|
|
42
|
+
reject(new Error("Water probe timed out; render an active AVBOIT water frame"));
|
|
43
|
+
}, 10000);
|
|
44
|
+
this.#probe = probe;
|
|
68
45
|
});
|
|
69
|
-
|
|
70
|
-
data.depth = pass.read(depth);
|
|
71
|
-
data.color = pass.write(pass.read(color));
|
|
72
|
-
|
|
73
|
-
return data.color;
|
|
74
46
|
}
|
|
75
47
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
#execute(data, resources, context, surfaces, camera) {
|
|
84
|
-
if (surfaces.length === 0) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const encoder = context.encoder;
|
|
89
|
-
const graphics = context.graphics;
|
|
90
|
-
|
|
91
|
-
const color_texture = resources.get(data.color);
|
|
92
|
-
const depth_texture = resources.get(data.depth);
|
|
93
|
-
|
|
94
|
-
const pipeline = this.#obtain_pipeline(color_texture.format);
|
|
95
|
-
|
|
96
|
-
const depth_view = depth_texture.obtainView();
|
|
97
|
-
|
|
98
|
-
// the height map is read at a coarser rate than its texels and clamped at the shore, which
|
|
99
|
-
// is what the upscale sampler is
|
|
100
|
-
const sampler = graphics.samplers.obtain(SAMPLER_LINEAR_UPSCALE);
|
|
101
|
-
|
|
102
|
-
/*
|
|
103
|
-
Every per-draw resource is built before the render pass opens: staging a uniform records a
|
|
104
|
-
copy onto the command encoder, and the encoder is locked while a render pass is open on it.
|
|
105
|
-
*/
|
|
106
|
-
const draws = [];
|
|
107
|
-
|
|
108
|
-
for (let i = 0; i < surfaces.length; i++) {
|
|
109
|
-
const surface = surfaces[i];
|
|
110
|
-
|
|
111
|
-
if (!surface.visible) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const height = graphics.textures.obtain(surface.height_texture);
|
|
48
|
+
dispose() {
|
|
49
|
+
this.#probe?.reject(new Error("Water system stopped"));
|
|
50
|
+
this.#probe = null;
|
|
51
|
+
this.#prepared = new WeakMap();
|
|
52
|
+
this.#inspection = new WeakMap();
|
|
53
|
+
}
|
|
116
54
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
color_shore:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
55
|
+
avboit_prepare({ graph, view_ctx, camera, color_texture, depth_texture, normal_texture,
|
|
56
|
+
hzb_texture, environment_texture }) {
|
|
57
|
+
const surfaces = this.surfaces.filter(s => s.visible && s.height_texture !== null)
|
|
58
|
+
.map(s => ({ ...s, extent: s.extent.slice(), height_uv: s.height_uv.slice(),
|
|
59
|
+
color_deep: s.color_deep.slice(), color_shore: s.color_shore.slice(),
|
|
60
|
+
shore_transition: s.shore_transition.slice(), extinction: s.extinction.slice() }))
|
|
61
|
+
.sort((a, b) => a.entity - b.entity);
|
|
62
|
+
surfaces.forEach((surface, index) => { surface.surface_id = index + 1; });
|
|
63
|
+
const settings = { ...this.settings };
|
|
64
|
+
const probe = this.#probe;
|
|
65
|
+
this.#probe = null;
|
|
66
|
+
const resolution = Array.from(view_ctx.resolution);
|
|
67
|
+
const data = { resolution, frame_time: surfaces[0]?.time ?? 0 };
|
|
68
|
+
const pipeline = this.#pipeline;
|
|
69
|
+
const pass = graph.add("Water / receivers", data, (data, resources, context) => {
|
|
70
|
+
const { encoder, graphics } = context;
|
|
71
|
+
const shared = {
|
|
72
|
+
camera: resources.get(data.camera),
|
|
73
|
+
trace: encoder.allocateTransientValueBuffer(WATER_TRACE_STRUCT, settings),
|
|
74
|
+
tDepth: resources.get(data.scene_depth).obtainView(DEFAULT_DEPTH_TEXTURE_VIEW),
|
|
75
|
+
tNormal: resources.get(data.normal).obtainView(),
|
|
76
|
+
tHZB: resources.get(data.hzb).obtainView(),
|
|
77
|
+
tScene: resources.get(data.color).obtainView(),
|
|
78
|
+
tEnvironment: resources.get(data.environment).obtainView(),
|
|
79
|
+
height_sampler: graphics.samplers.obtain(SAMPLER_LINEAR_UPSCALE),
|
|
80
|
+
};
|
|
81
|
+
// Copies/uniform uploads must be encoded before opening the render pass.
|
|
82
|
+
const draws = surfaces.map(s => WATER_RESOURCES.generateBindings({ ...shared,
|
|
83
|
+
water: encoder.allocateTransientValueBuffer(WATER_DRAW_STRUCT, s),
|
|
84
|
+
terrain_height: graphics.textures.obtain(s.height_texture).obtainView(),
|
|
85
|
+
}, encoder));
|
|
86
|
+
const render = encoder.constructRenderPass({ label: "Water / receivers", pipeline, bindings: [],
|
|
87
|
+
colorAttachments: [data.receiver, data.trace_metadata].map(handle => ({
|
|
88
|
+
view: resources.get(handle).obtainView(), loadOp: "clear", storeOp: "store", clearValue: [0,0,0,0],
|
|
89
|
+
})),
|
|
90
|
+
depthStencilAttachment: { view: resources.get(data.interface_depth).obtainView(DEFAULT_DEPTH_TEXTURE_VIEW),
|
|
91
|
+
depthLoadOp: "clear", depthStoreOp: "store", depthClearValue: 0 },
|
|
129
92
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
93
|
+
for (const bindings of draws) { graphics.setPipelineBindings(render, pipeline, bindings); render.draw(6); }
|
|
94
|
+
render.end();
|
|
95
|
+
});
|
|
96
|
+
for (const [name, handle] of Object.entries({ camera, color: color_texture, scene_depth: depth_texture,
|
|
97
|
+
normal: normal_texture, hzb: hzb_texture, environment: environment_texture })) { data[name] = pass.read(handle); }
|
|
98
|
+
const target = (name, format) => pass.create(`Water ${name}`, TextureResourceDescriptor.from({
|
|
99
|
+
resolution, format, usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
100
|
+
| (probe !== null && format !== "depth32float" ? GPUTextureUsage.COPY_SRC : 0),
|
|
101
|
+
}));
|
|
102
|
+
// Keep the accepted UV and both paths at f32 precision through final shading.
|
|
103
|
+
data.receiver = target("receiver", "rgba32float");
|
|
104
|
+
data.trace_metadata = target("trace metadata", "rgba32float");
|
|
105
|
+
data.interface_depth = target("interface depth", "depth32float");
|
|
106
|
+
let states = this.#prepared.get(graph);
|
|
107
|
+
if (states === undefined) { states = new Map(); this.#prepared.set(graph, states); }
|
|
108
|
+
states.set(camera, data);
|
|
109
|
+
if (settings.debug_view !== 0) {
|
|
110
|
+
let views = this.#inspection.get(graph);
|
|
111
|
+
if (views === undefined) { views = new Map(); this.#inspection.set(graph, views); }
|
|
112
|
+
views.set(view_ctx, { data, mode: settings.debug_view, resolution });
|
|
113
|
+
}
|
|
114
|
+
const visibility_resolution = resolution.map(v => Math.ceil(v / 4));
|
|
115
|
+
const [seeds] = graph_image_pass({ graph, shader: shader_water_confidence_seed,
|
|
116
|
+
inputs: { trace_metadata: data.trace_metadata, scene_depth: data.scene_depth }, output_resolution: visibility_resolution });
|
|
117
|
+
const [horizontal] = graph_image_pass({ graph, shader: shader_water_confidence_x,
|
|
118
|
+
inputs: { distance_field: seeds }, output_resolution: visibility_resolution });
|
|
119
|
+
const [visibility_distance] = graph_image_pass({ graph, shader: shader_water_confidence_y,
|
|
120
|
+
inputs: { distance_field: horizontal }, output_resolution: visibility_resolution });
|
|
121
|
+
data.visibility_distance = visibility_distance;
|
|
122
|
+
const finalize_data = {};
|
|
123
|
+
const finalize_pipeline = this.#finalize_pipeline;
|
|
124
|
+
const finalize = graph.add('Water / coherent optics', finalize_data, (d, resources, {encoder, graphics}) => {
|
|
125
|
+
const shared = {
|
|
126
|
+
camera: resources.get(d.camera), trace: encoder.allocateTransientValueBuffer(WATER_TRACE_STRUCT, settings),
|
|
127
|
+
tDepth: resources.get(d.scene_depth).obtainView(DEFAULT_DEPTH_TEXTURE_VIEW),
|
|
128
|
+
tNormal: resources.get(d.normal).obtainView(), tHZB: resources.get(d.hzb).obtainView(),
|
|
129
|
+
tScene: resources.get(d.color).obtainView(), tEnvironment: resources.get(d.environment).obtainView(),
|
|
130
|
+
receiver: resources.get(d.receiver).obtainView(), trace_metadata: resources.get(d.trace_metadata).obtainView(),
|
|
131
|
+
visibility_distance: resources.get(d.visibility_distance).obtainView(),
|
|
132
|
+
height_sampler: graphics.samplers.obtain(SAMPLER_LINEAR_UPSCALE),
|
|
133
|
+
};
|
|
134
|
+
const draws = surfaces.map(s => WATER_FINALIZE_RESOURCES.generateBindings({...shared,
|
|
135
|
+
water: encoder.allocateTransientValueBuffer(WATER_DRAW_STRUCT, s),
|
|
136
|
+
terrain_height: graphics.textures.obtain(s.height_texture).obtainView(),
|
|
137
137
|
}, encoder));
|
|
138
|
+
const copy_pipeline = shader_water_background_copy.pipeline;
|
|
139
|
+
const copy_bindings = shader_water_background_copy.descriptor.resources.generateBindings({tScene: shared.tScene}, encoder);
|
|
140
|
+
const render = encoder.constructRenderPass({label: 'Water / coherent optics', pipeline: finalize_pipeline, bindings: [],
|
|
141
|
+
colorAttachments: [d.transmission,d.radiance,d.background].map(handle => ({
|
|
142
|
+
view: resources.get(handle).obtainView(), loadOp: 'clear', storeOp: 'store', clearValue: [0,0,0,0],
|
|
143
|
+
})), depthStencilAttachment: {view: resources.get(d.interface_depth).obtainView(DEFAULT_DEPTH_TEXTURE_VIEW), depthReadOnly: true},
|
|
144
|
+
});
|
|
145
|
+
render.setPipeline(graphics.render_pipelines.obtain(copy_pipeline)); render.record_pipeline(copy_pipeline);
|
|
146
|
+
graphics.setPipelineBindings(render, copy_pipeline, copy_bindings); render.draw(3);
|
|
147
|
+
render.setPipeline(graphics.render_pipelines.obtain(finalize_pipeline)); render.record_pipeline(finalize_pipeline);
|
|
148
|
+
for (const bindings of draws) { graphics.setPipelineBindings(render, finalize_pipeline, bindings); render.draw(6); }
|
|
149
|
+
render.end();
|
|
150
|
+
});
|
|
151
|
+
for (const key of ['camera','scene_depth','normal','hzb','color','environment','receiver','trace_metadata','visibility_distance','interface_depth']) {
|
|
152
|
+
finalize_data[key] = finalize.read(data[key]);
|
|
138
153
|
}
|
|
154
|
+
const optical_target = (name,format) => finalize.create(`Water ${name}`, TextureResourceDescriptor.from({
|
|
155
|
+
resolution, format, usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
156
|
+
| (probe !== null ? GPUTextureUsage.COPY_SRC : 0),
|
|
157
|
+
}));
|
|
158
|
+
data.transmission = finalize_data.transmission = optical_target('transmission','rgba32float');
|
|
159
|
+
data.radiance = finalize_data.radiance = optical_target('radiance','rgba16float');
|
|
160
|
+
const background_color = finalize_data.background = optical_target('background','rgba16float');
|
|
161
|
+
if (probe !== null) { this.#record_probe(graph, data, resolution, probe); }
|
|
162
|
+
return { background_color };
|
|
163
|
+
}
|
|
139
164
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
165
|
+
#state(graph, camera) {
|
|
166
|
+
const data = this.#prepared.get(graph)?.get(camera);
|
|
167
|
+
if (data === undefined) { throw new Error("Water AVBOIT requires preparation in this graph/view"); }
|
|
168
|
+
return data;
|
|
169
|
+
}
|
|
143
170
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
storeOp: "store",
|
|
152
|
-
view: color_texture.obtainView(TextureViewDescriptor.from({
|
|
153
|
-
mipLevelCount: 1,
|
|
154
|
-
baseMipLevel: 0
|
|
155
|
-
}))
|
|
156
|
-
}]
|
|
157
|
-
});
|
|
171
|
+
avboit_occupancy({ graph, camera, cluster_parameters, occupancy }) {
|
|
172
|
+
const data = this.#state(graph, camera);
|
|
173
|
+
const { occupancy: out } = graph_compute_pass({ graph, shader: shader_water_occupancy,
|
|
174
|
+
bindings: { camera, settings: { cluster_parameters }, interface_depth: data.interface_depth, occupancy },
|
|
175
|
+
group_count: [Math.ceil(data.resolution[0] / 8), Math.ceil(data.resolution[1] / 8), 1] });
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
158
178
|
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
avboit_splat({ graph, camera, warp, voxel_resolution, volume }) {
|
|
180
|
+
const data = this.#state(graph, camera);
|
|
181
|
+
const out = graph_compute_pass({ graph, shader: shader_water_splat,
|
|
182
|
+
bindings: { camera, warp, interface_depth: data.interface_depth, transmission: data.transmission,
|
|
183
|
+
extinction_volume: volume.extinction, overflow_slice: volume.overflow },
|
|
184
|
+
group_count: [Math.ceil(voxel_resolution[0]/8), Math.ceil(voxel_resolution[1]/8), 1] });
|
|
185
|
+
return { extinction: out.extinction_volume, overflow: out.overflow_slice, dummy: volume.dummy };
|
|
186
|
+
}
|
|
161
187
|
|
|
162
|
-
|
|
188
|
+
avboit_draw({ graph, view_ctx, camera, warp, integral, volumetrics_lut, volumetrics_metadata, accumulators }) {
|
|
189
|
+
const optical = this.#state(graph, camera);
|
|
190
|
+
// Inspection consumes the same completed shared integral as the production contribution.
|
|
191
|
+
optical.warp = warp; optical.integral = integral;
|
|
192
|
+
const data = {};
|
|
193
|
+
const pass = graph.add("Water / AVBOIT draw", data, (data, resources, { encoder, graphics }) => {
|
|
194
|
+
shader_water_draw.draw({ encoder, bindings: {
|
|
195
|
+
camera: resources.get(data.camera), view: view_ctx.uniform_buffer.buffer,
|
|
196
|
+
warp: resources.get(data.warp), interface_depth: resources.get(data.interface_depth).obtainView(DEFAULT_DEPTH_TEXTURE_VIEW),
|
|
197
|
+
transmission: resources.get(data.transmission).obtainView(), radiance: resources.get(data.radiance).obtainView(),
|
|
198
|
+
tIntegral: resources.get(data.integral).obtainView(), sLinear: graphics.samplers.obtain(SAMPLER_LINEAR_UPSCALE),
|
|
199
|
+
volumetrics_metadata: resources.get(data.volumetrics_metadata), tVolumetrics: resources.get(data.volumetrics_lut).obtainView(),
|
|
200
|
+
tSTBN_vec3: graphics.textures.obtain(STATIC_GRAPHICS_ENGINE_ASSETS.stbn_vec3).obtainView(),
|
|
201
|
+
}, colorAttachments: [data.color,data.norm,data.extinction,data.emission].map(handle => ({
|
|
202
|
+
view: resources.get(handle).obtainView(), loadOp: "load", storeOp: "store",
|
|
203
|
+
})) });
|
|
204
|
+
});
|
|
205
|
+
for (const [key,handle] of Object.entries({camera,warp,integral,volumetrics_lut,volumetrics_metadata,
|
|
206
|
+
interface_depth: optical.interface_depth, transmission: optical.transmission, radiance: optical.radiance})) {
|
|
207
|
+
data[key] = pass.read(handle);
|
|
163
208
|
}
|
|
209
|
+
for (const [key,handle] of Object.entries(accumulators)) { data[key] = pass.write(pass.read(handle)); }
|
|
210
|
+
this.#prepared.get(graph).delete(camera);
|
|
211
|
+
return { color: data.color, norm: data.norm, extinction: data.extinction, emission: data.emission };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Debug presentation only: called after shared resolve, never sampled by production optics. */
|
|
215
|
+
inspect(graph, view_ctx, output_resolution) {
|
|
216
|
+
const views = this.#inspection.get(graph);
|
|
217
|
+
const state = views?.get(view_ctx);
|
|
218
|
+
if (state === undefined) { return undefined; }
|
|
219
|
+
views.delete(view_ctx);
|
|
220
|
+
const { data, mode } = state;
|
|
221
|
+
const resolution = output_resolution ?? state.resolution;
|
|
222
|
+
const [color] = graph_image_pass({ graph, shader: shader_water_debug, output_resolution: resolution,
|
|
223
|
+
inputs: { inspection: { mode, resolution }, camera: data.camera, warp: data.warp, tIntegral: data.integral,
|
|
224
|
+
transmission: data.transmission, radiance: data.radiance,
|
|
225
|
+
receiver: data.receiver, interface_depth: data.interface_depth, trace_metadata: data.trace_metadata } });
|
|
226
|
+
return color;
|
|
227
|
+
}
|
|
164
228
|
|
|
165
|
-
|
|
229
|
+
#record_probe(graph, optical, resolution, probe) {
|
|
230
|
+
const data = {};
|
|
231
|
+
const pass = graph.add("Water / pixel probe", data, (data, resources, { encoder, graphics }) => {
|
|
232
|
+
const buffer = graphics.device.createBuffer({ size: 1024, usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST });
|
|
233
|
+
const pixel = probe.uv.map((v, i) => Math.min(resolution[i]-1, Math.max(0, Math.floor(v*resolution[i]))));
|
|
234
|
+
[data.receiver, data.transmission, data.radiance, data.trace_metadata].forEach((handle, i) => {
|
|
235
|
+
encoder.copyTextureToBuffer({ texture: resources.get(handle).gpu_texture, origin: [...pixel, 0] },
|
|
236
|
+
{ buffer, offset: i*256, bytesPerRow: 256 }, [1,1,1]);
|
|
237
|
+
});
|
|
238
|
+
encoder.done.then(async () => {
|
|
239
|
+
try {
|
|
240
|
+
await buffer.mapAsync(GPUMapMode.READ);
|
|
241
|
+
const mapped = buffer.getMappedRange();
|
|
242
|
+
const half = offset => Array.from(new Uint16Array(mapped, offset, 4), half_to_float_uint16);
|
|
243
|
+
const radiance = half(512);
|
|
244
|
+
const confidence = radiance[3];
|
|
245
|
+
radiance[3] = new Float32Array(mapped, 768, 4)[1];
|
|
246
|
+
probe.resolve({ pixel, resolution, frame_time: optical.frame_time, receiver: Array.from(new Float32Array(mapped, 0, 4)),
|
|
247
|
+
transmission: Array.from(new Float32Array(mapped, 256, 4)), radiance, confidence, stale: false });
|
|
248
|
+
} catch (error) { probe.reject(error); }
|
|
249
|
+
finally { buffer.destroy(); }
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
for (const key of ["receiver", "transmission", "radiance", "trace_metadata"]) { data[key] = pass.read(optical[key]); }
|
|
253
|
+
pass.make_side_effect();
|
|
166
254
|
}
|
|
167
255
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const chunk_water_refraction_confidence: CodeChunk;
|
|
2
|
+
export const chunk_water_transport: CodeChunk;
|
|
3
|
+
export const chunk_water_receiver_radiance: CodeChunk;
|
|
4
|
+
import { CodeChunk } from '../shader/compiler/CodeChunk.js';
|
|
5
|
+
//# sourceMappingURL=chunk_water_transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk_water_transport.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/water/chunk_water_transport.js"],"names":[],"mappings":"AAKA,0DAeG;AAEH,8CAoBG;AAIH,sDA+CoF;0BA7F1D,iCAAiC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { CodeChunk } from '../shader/compiler/CodeChunk.js';
|
|
2
|
+
import { chunk_decode_g_buffer_normal } from '../shader/chunk/geometry/normal/chunk_decode_g_buffer_normal.js';
|
|
3
|
+
import { chunk_inv_project_position } from '../shader/chunk/screen_space/chunk_inv_project_position.js';
|
|
4
|
+
import { chunk_is_background } from '../shader/chunk/depth/chunk_is_background.js';
|
|
5
|
+
|
|
6
|
+
export const chunk_water_refraction_confidence = CodeChunk.from(/* language=WGSL */ `
|
|
7
|
+
fn water_refraction_lookup(original: vec2f, receiver: vec2f, confidence: f32) -> vec2f {
|
|
8
|
+
return mix(original, receiver, clamp(confidence, 0.0, 1.0));
|
|
9
|
+
}
|
|
10
|
+
fn water_refraction_confidence(uv: vec2f, original_uv: vec2f, size: vec2f, distance_tiles: f32) -> f32 {
|
|
11
|
+
let displacement = length((uv - original_uv) * size);
|
|
12
|
+
let fade_width = clamp(displacement, 8.0, 64.0);
|
|
13
|
+
let visibility = smoothstep(0.0, fade_width, distance_tiles * 4.0);
|
|
14
|
+
let source_edge = min(min(original_uv.x, original_uv.y), min(1.0-original_uv.x, 1.0-original_uv.y));
|
|
15
|
+
let receiver_edge = min(min(uv.x, uv.y), min(1.0-uv.x, 1.0-uv.y));
|
|
16
|
+
// Approaching an off-screen receiver must approach the control lookup continuously,
|
|
17
|
+
// even while the water fragment itself is far enough from the frame border.
|
|
18
|
+
return visibility * smoothstep(0.0, clamp(displacement / min(size.x, size.y), 0.01, 0.1),
|
|
19
|
+
min(source_edge, receiver_edge));
|
|
20
|
+
}
|
|
21
|
+
`);
|
|
22
|
+
|
|
23
|
+
export const chunk_water_transport = CodeChunk.from(/* language=WGSL */ `
|
|
24
|
+
struct WaterEvent { transmission: vec3f, radiance: vec3f }
|
|
25
|
+
struct WaterTransport { transmission: vec3f, radiance: vec3f, background: vec3f }
|
|
26
|
+
fn water_event(path: f32, extinction: vec3f, fresnel: f32, reflection: vec3f, body: vec3f) -> WaterEvent {
|
|
27
|
+
let absorption = exp(-max(extinction, vec3f(0.0)) * max(path, 0.0));
|
|
28
|
+
let raw = (1.0 - fresnel) * absorption;
|
|
29
|
+
let t = max(raw, vec3f(1e-6));
|
|
30
|
+
let scale = (1.0 - t) / max(1.0 - raw, vec3f(1e-20));
|
|
31
|
+
return WaterEvent(t, scale * (fresnel * reflection + (1.0-fresnel) * (1.0-absorption) * body));
|
|
32
|
+
}
|
|
33
|
+
// One selected lookup and its optical event. Only geometric coverage mixes images;
|
|
34
|
+
// fading refraction interpolates the lookup UV before sampling, never two displaced colors.
|
|
35
|
+
fn water_transport(event: WaterEvent, original: vec3f, receiver: vec3f,
|
|
36
|
+
coverage: f32) -> WaterTransport {
|
|
37
|
+
let a = clamp(coverage, 0.0, 1.0);
|
|
38
|
+
let t = (1.0-a) + a * event.transmission;
|
|
39
|
+
let w = a * event.radiance;
|
|
40
|
+
let background = ((1.0-a)*original + a*event.transmission*receiver) / t;
|
|
41
|
+
return WaterTransport(t, w, background);
|
|
42
|
+
}
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
// Filtering radiance across a silhouette must not introduce a surface that the ray never hit.
|
|
46
|
+
// The center depth/face normal define receiver ownership; taps must lie on that same local plane.
|
|
47
|
+
export const chunk_water_receiver_radiance = CodeChunk.from(/* language=WGSL */ `
|
|
48
|
+
// Depth is stored at the texel center. Intersect the lookup's camera ray with that
|
|
49
|
+
// local plane so subpixel lookup motion does not quantize water thickness.
|
|
50
|
+
fn water_receiver_path(depth: texture_2d<f32>, normals: texture_2d<u32>, uv: vec2f,
|
|
51
|
+
inverse_projection: mat4x4f, world_to_view: mat4x4f, origin: vec3f) -> f32 {
|
|
52
|
+
let size = vec2f(textureDimensions(depth, 0));
|
|
53
|
+
let coord = clamp(vec2i(uv*size), vec2i(0), vec2i(size)-1);
|
|
54
|
+
let d = textureLoad(depth, coord, 0).r;
|
|
55
|
+
let p = inv_project_position(vec3f((vec2f(coord)+0.5)/size,d), inverse_projection);
|
|
56
|
+
let direction = inv_project_position(vec3f(uv,d), inverse_projection);
|
|
57
|
+
let n = (world_to_view * vec4f(decode_g_buffer_normal(textureLoad(normals,coord,0).zw),0.0)).xyz;
|
|
58
|
+
let denominator = dot(n,direction);
|
|
59
|
+
if (abs(denominator) <= 1e-6) { return distance(origin,p); }
|
|
60
|
+
return distance(origin, direction * (dot(n,p)/denominator));
|
|
61
|
+
}
|
|
62
|
+
fn water_receiver_radiance(scene: texture_2d<f32>, depth: texture_2d<f32>, normals: texture_2d<u32>,
|
|
63
|
+
uv: vec2f, inverse_projection: mat4x4f, inverse_view: mat4x4f, level: f32, below_interface: bool) -> vec4f {
|
|
64
|
+
let size = vec2i(textureDimensions(depth, 0));
|
|
65
|
+
let center = clamp(vec2i(uv * vec2f(size)), vec2i(0), size-1);
|
|
66
|
+
let center_depth = textureLoad(depth, center, 0).r;
|
|
67
|
+
if (is_background(center_depth)) { return vec4f(0.0); }
|
|
68
|
+
let center_vs = inv_project_position(vec3f((vec2f(center)+0.5)/vec2f(size), center_depth), inverse_projection);
|
|
69
|
+
let p = (inverse_view * vec4f(center_vs, 1.0)).xyz;
|
|
70
|
+
let n = decode_g_buffer_normal(textureLoad(normals, center, 0).zw);
|
|
71
|
+
if (below_interface && p.y > level + 0.02) { return vec4f(0.0); }
|
|
72
|
+
let texel = uv * vec2f(size) - 0.5;
|
|
73
|
+
let base = vec2i(floor(texel));
|
|
74
|
+
let f = fract(texel);
|
|
75
|
+
var color = vec3f(0.0);
|
|
76
|
+
var weight = 0.0;
|
|
77
|
+
for (var y = 0; y < 2; y++) {
|
|
78
|
+
for (var x = 0; x < 2; x++) {
|
|
79
|
+
let coord = clamp(base + vec2i(x,y), vec2i(0), size-1);
|
|
80
|
+
let d = textureLoad(depth, coord, 0).r;
|
|
81
|
+
if (is_background(d)) { continue; }
|
|
82
|
+
let tap_vs = inv_project_position(vec3f((vec2f(coord)+0.5)/vec2f(size), d), inverse_projection);
|
|
83
|
+
let tap = (inverse_view * vec4f(tap_vs, 1.0)).xyz;
|
|
84
|
+
let tap_n = decode_g_buffer_normal(textureLoad(normals, coord, 0).zw);
|
|
85
|
+
if ((below_interface && tap.y > level+0.02) || dot(n,tap_n) < 0.95
|
|
86
|
+
|| abs(dot(tap-p,n)) > 0.02) { continue; }
|
|
87
|
+
let w = select(1.0-f.x, f.x, x == 1) * select(1.0-f.y, f.y, y == 1);
|
|
88
|
+
color += w * textureLoad(scene, coord, 0).rgb;
|
|
89
|
+
weight += w;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return vec4f(color / max(weight, 1e-20), weight);
|
|
93
|
+
}
|
|
94
|
+
`, [chunk_decode_g_buffer_normal, chunk_inv_project_position, chunk_is_background]);
|
|
@@ -1,33 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* **It has no depth attachment, and that is forced rather than chosen.** The shader *samples* scene
|
|
5
|
-
* depth to know how much water the view looks through, and a texture may not be a sampled source
|
|
6
|
-
* and a render attachment in the same pass. So the depth test the hardware would have done is done
|
|
7
|
-
* in the shader instead — which is also why the fragment `discard` there is load-bearing rather
|
|
8
|
-
* than a guard: without it, water would draw over the things standing in it.
|
|
9
|
-
*
|
|
10
|
-
* @param {object} [options]
|
|
11
|
-
* @param {string} [options.color_format]
|
|
12
|
-
* @returns {RenderPipelineDescriptor}
|
|
13
|
-
*/
|
|
14
|
-
export function create_water_pipeline({ color_format }?: {
|
|
15
|
-
color_format?: string;
|
|
16
|
-
}): RenderPipelineDescriptor;
|
|
17
|
-
/**
|
|
18
|
-
* One water surface. Small, and rewritten per surface per frame rather than tabled — a level has a
|
|
19
|
-
* handful of these, not thousands.
|
|
20
|
-
*/
|
|
1
|
+
export function create_water_pipeline(): RenderPipelineDescriptor;
|
|
2
|
+
export function create_water_finalize_pipeline(): RenderPipelineDescriptor;
|
|
21
3
|
export const WATER_DRAW_STRUCT: WebGPUStruct;
|
|
4
|
+
export const WATER_TRACE_STRUCT: WebGPUStruct;
|
|
5
|
+
export const WATER_FINALIZE_RESOURCES: ShaderResourceSetDescriptor;
|
|
6
|
+
export const water_transport_fallback: CodeChunk;
|
|
7
|
+
export const chunk_water_screen_ray: CodeChunk;
|
|
22
8
|
export const water_shader: ShaderDescriptor;
|
|
23
|
-
|
|
24
|
-
* The pipeline's resource set, for building bind groups.
|
|
25
|
-
*
|
|
26
|
-
* @type {ShaderResourceSetDescriptor}
|
|
27
|
-
*/
|
|
9
|
+
export const water_finalize_shader: ShaderDescriptor;
|
|
28
10
|
export const WATER_RESOURCES: ShaderResourceSetDescriptor;
|
|
29
11
|
import { RenderPipelineDescriptor } from "../../descriptor/pipeline/render/RenderPipelineDescriptor.js";
|
|
30
12
|
import { WebGPUStruct } from "../shader/type/WebGPUStruct.js";
|
|
31
|
-
import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
|
|
32
13
|
import { ShaderResourceSetDescriptor } from "../shader/resource/ShaderResourceSetDescriptor.js";
|
|
14
|
+
import { CodeChunk } from "../shader/compiler/CodeChunk.js";
|
|
15
|
+
import { ShaderDescriptor } from "../shader/ShaderDescriptor.js";
|
|
33
16
|
//# sourceMappingURL=shader_water.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader_water.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/water/shader_water.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shader_water.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/water/shader_water.js"],"names":[],"mappings":"AA8XA,kEAAuH;AACvH,2EAAuJ;AA3WvJ,6CAKuB;AAEvB,8CAGwB;AAmBxB,mEAA8D;AAE9D,iDAIG;AAsCH,+CAmGoH;AA8KpH,4CAAmG;AACnG,qDAA2J;AAC3J,0DAAyC;yCA9WA,8DAA8D;6BAe1E,gCAAgC;4CAHjB,mDAAmD;0BADrE,iCAAiC;iCAE1B,+BAA+B"}
|