@woosh/meep-engine 3.37.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/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/skinning/bounds_refresh/shader_meshlet_bounds_reduce.d.ts.map +1 -1
- 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_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/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/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/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_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_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/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/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/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/shader/chunk/geometry/plane/plane_ray_raycast.d.ts.map +0 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CodeChunk } from "../../compiler/CodeChunk.js";
|
|
2
|
+
import { chunk_is_background } from "../depth/chunk_is_background.js";
|
|
3
|
+
import { chunk_decode_g_buffer_normal } from "../geometry/normal/chunk_decode_g_buffer_normal.js";
|
|
4
|
+
import { chunk_plane_from_normal_and_point } from "../geometry/plane/chunk_plane_from_normal_and_point.js";
|
|
5
|
+
import { chunk_plane_ray_raycast } from "../geometry/plane/chunk_plane_ray_raycast.js";
|
|
6
|
+
import { RAY_STRUCT } from "../geometry/ray/RAY_STRUCT.js";
|
|
7
|
+
import { chunk_ray_at } from "../geometry/ray/chunk_ray_at.js";
|
|
8
|
+
import { chunk_ray_nearest_point } from "../geometry/ray/chunk_ray_nearest_point.js";
|
|
9
|
+
import { chunk_inv_project_position } from "./chunk_inv_project_position.js";
|
|
10
|
+
import { chunk_project_position } from "./chunk_project_position.js";
|
|
11
|
+
|
|
12
|
+
/** Mayer et al. 2026 tangent-plane refinement. All arithmetic is in matrix view space. */
|
|
13
|
+
export const chunk_screen_space_newton_ray = CodeChunk.from(/* language=WGSL */ `
|
|
14
|
+
struct ScreenSpaceRayHit {
|
|
15
|
+
uv: vec2<f32>,
|
|
16
|
+
distance: f32,
|
|
17
|
+
residual: f32,
|
|
18
|
+
iterations: u32,
|
|
19
|
+
// 0 hit, 1 bounds/clip, 2 sky, 3 parallel/invalid, 4 interval, 5 exhausted/residual
|
|
20
|
+
status: u32,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fn screen_space_ray_in_bounds(uv: vec2<f32>) -> bool {
|
|
24
|
+
return all(uv >= vec2<f32>(0.0)) && all(uv < vec2<f32>(1.0));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn screen_space_ray_projectable(p: vec3<f32>, projection: mat4x4<f32>) -> bool {
|
|
28
|
+
let clip = projection * vec4<f32>(p, 1.0);
|
|
29
|
+
return clip.w > 1e-6 && all(abs(clip) < vec4<f32>(1e30));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Reconstruct the receiver at the subpixel lookup on its local tangent plane.
|
|
33
|
+
// A texel-center position is a different surface point: projecting its nearest
|
|
34
|
+
// point on the ray can exceed one pixel at grazing angles even for an exact hit.
|
|
35
|
+
fn screen_space_ray_validate(
|
|
36
|
+
ray: Ray, uv: vec2<f32>, depth: texture_2d<f32>, normals: texture_2d<u32>,
|
|
37
|
+
projection: mat4x4<f32>, inverse_projection: mat4x4<f32>, world_to_view: mat4x4<f32>,
|
|
38
|
+
distance_tolerance: f32,
|
|
39
|
+
) -> ScreenSpaceRayHit {
|
|
40
|
+
var hit = ScreenSpaceRayHit(uv, 0.0, 1e20, 0u, 1u);
|
|
41
|
+
if (!screen_space_ray_in_bounds(uv)) { return hit; }
|
|
42
|
+
let size = textureDimensions(depth, 0);
|
|
43
|
+
let coord = vec2<i32>(uv * vec2<f32>(size));
|
|
44
|
+
let d = textureLoad(depth, coord, 0).r;
|
|
45
|
+
if (is_background(d)) { hit.status = 2u; return hit; }
|
|
46
|
+
let center = (vec2<f32>(coord) + 0.5) / vec2<f32>(size);
|
|
47
|
+
let center_position = inv_project_position(vec3<f32>(center, d), inverse_projection);
|
|
48
|
+
let normal = (world_to_view * vec4f(decode_g_buffer_normal(textureLoad(normals, coord, 0).zw), 0.0)).xyz;
|
|
49
|
+
let lookup_ray = inv_project_position(vec3f(uv, d), inverse_projection);
|
|
50
|
+
let denominator = dot(normal, lookup_ray);
|
|
51
|
+
if (!(abs(denominator) > 1e-6)) { hit.status = 3u; return hit; }
|
|
52
|
+
let scale = dot(normal, center_position) / denominator;
|
|
53
|
+
if (!(scale > 0.0)) { hit.status = 3u; return hit; }
|
|
54
|
+
let p = lookup_ray * scale;
|
|
55
|
+
let travel = dot(p - ray.origin, ray.direction);
|
|
56
|
+
hit.distance = travel;
|
|
57
|
+
if (!(travel > 1e-4 && travel <= ray.tmax)) { hit.status = 4u; return hit; }
|
|
58
|
+
let nearest = ray_nearest_point(ray, p);
|
|
59
|
+
if (!screen_space_ray_projectable(nearest, projection)) { return hit; }
|
|
60
|
+
let pixel_error = length((project_position(nearest, projection).xy - uv) * vec2<f32>(size));
|
|
61
|
+
hit.residual = distance(p, nearest);
|
|
62
|
+
hit.status = 5u;
|
|
63
|
+
if (pixel_error <= 1.0 && hit.residual <= distance_tolerance) { hit.status = 0u; }
|
|
64
|
+
return hit;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn screen_space_newton_ray(
|
|
68
|
+
ray: Ray, seed_uv: vec2<f32>, depth: texture_2d<f32>, normals: texture_2d<u32>,
|
|
69
|
+
projection: mat4x4<f32>, inverse_projection: mat4x4<f32>, world_to_view: mat4x4<f32>,
|
|
70
|
+
max_updates: u32, distance_tolerance: f32,
|
|
71
|
+
) -> ScreenSpaceRayHit {
|
|
72
|
+
var uv = seed_uv;
|
|
73
|
+
var hit = ScreenSpaceRayHit(uv, 0.0, 1e20, 0u, 5u);
|
|
74
|
+
let size = textureDimensions(depth, 0);
|
|
75
|
+
for (var i = 0u; i < min(max_updates, 16u); i++) {
|
|
76
|
+
hit.iterations = i + 1u;
|
|
77
|
+
if (!screen_space_ray_in_bounds(uv)) { hit.status = 1u; return hit; }
|
|
78
|
+
let coord = vec2<i32>(uv * vec2<f32>(size));
|
|
79
|
+
let d = textureLoad(depth, coord, 0).r;
|
|
80
|
+
if (is_background(d)) { hit.status = 2u; return hit; }
|
|
81
|
+
let center = (vec2<f32>(coord) + 0.5) / vec2<f32>(size);
|
|
82
|
+
let receiver = inv_project_position(vec3<f32>(center, d), inverse_projection);
|
|
83
|
+
// .zw is the geometric face normal; .xy includes material normal mapping.
|
|
84
|
+
let world_normal = decode_g_buffer_normal(textureLoad(normals, coord, 0).zw);
|
|
85
|
+
let normal = (world_to_view * vec4<f32>(world_normal, 0.0)).xyz;
|
|
86
|
+
if (!(abs(dot(ray.direction, normal)) > 1e-4)) { hit.status = 3u; return hit; }
|
|
87
|
+
let plane = plane_from_normal_and_point(normal, receiver);
|
|
88
|
+
let travel = plane_ray_raycast(ray.origin, ray.direction, plane);
|
|
89
|
+
if (!(travel > 1e-4 && travel <= ray.tmax)) { hit.status = 4u; return hit; }
|
|
90
|
+
let next = ray_at(ray.origin, ray.direction, travel);
|
|
91
|
+
if (!screen_space_ray_projectable(next, projection)) { hit.status = 1u; return hit; }
|
|
92
|
+
uv = project_position(next, projection).xy;
|
|
93
|
+
hit = screen_space_ray_validate(ray, uv, depth, normals, projection, inverse_projection, world_to_view, distance_tolerance);
|
|
94
|
+
hit.iterations = i + 1u;
|
|
95
|
+
if (hit.status == 0u || hit.status == 1u || hit.status == 2u) { return hit; }
|
|
96
|
+
}
|
|
97
|
+
return hit;
|
|
98
|
+
}
|
|
99
|
+
`, [RAY_STRUCT.declaration_chunk, chunk_is_background, chunk_decode_g_buffer_normal,
|
|
100
|
+
chunk_plane_from_normal_and_point, chunk_plane_ray_raycast, chunk_ray_at,
|
|
101
|
+
chunk_ray_nearest_point, chunk_inv_project_position, chunk_project_position]);
|
|
@@ -1,33 +1,66 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Draws water surfaces over a lit frame.
|
|
3
|
-
*
|
|
4
|
-
* **Water is a transparent pass on top of opaque**, which is why it lives here rather than in the
|
|
5
|
-
* material system: it is not shaded, it does not write the G-buffer, and it needs the finished
|
|
6
|
-
* depth of everything behind it in order to know how much water the view is looking through.
|
|
7
|
-
*
|
|
8
|
-
* The pass reads scene depth and writes the frame's colour, so it belongs at
|
|
9
|
-
* {@link FramePhase.AfterLighting} — opaque surfaces lit and composited, transparency not yet run.
|
|
10
|
-
*/
|
|
1
|
+
/** Production water channel. Only AVBOIT's shared resolve composites its radiance. */
|
|
11
2
|
export class GPUWaterRenderer {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
3
|
+
surfaces: any[];
|
|
4
|
+
settings: {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
max_distance: number;
|
|
7
|
+
distance_tolerance: number;
|
|
8
|
+
max_updates: number;
|
|
9
|
+
fallback_steps: number;
|
|
10
|
+
mode: number;
|
|
11
|
+
reflections: number;
|
|
12
|
+
debug_view: number;
|
|
13
|
+
};
|
|
14
|
+
avboit_is_empty(): boolean;
|
|
15
|
+
/** Optional single-pixel readback on the next rendered water frame. No per-frame readback. */
|
|
16
|
+
request_probe(uv: any): Promise<any>;
|
|
17
|
+
dispose(): void;
|
|
18
|
+
avboit_prepare({ graph, view_ctx, camera, color_texture, depth_texture, normal_texture, hzb_texture, environment_texture }: {
|
|
19
|
+
graph: any;
|
|
20
|
+
view_ctx: any;
|
|
21
|
+
camera: any;
|
|
22
|
+
color_texture: any;
|
|
23
|
+
depth_texture: any;
|
|
24
|
+
normal_texture: any;
|
|
25
|
+
hzb_texture: any;
|
|
26
|
+
environment_texture: any;
|
|
27
|
+
}): {
|
|
28
|
+
background_color: any;
|
|
29
|
+
};
|
|
30
|
+
avboit_occupancy({ graph, camera, cluster_parameters, occupancy }: {
|
|
31
|
+
graph: any;
|
|
32
|
+
camera: any;
|
|
33
|
+
cluster_parameters: any;
|
|
34
|
+
occupancy: any;
|
|
35
|
+
}): any;
|
|
36
|
+
avboit_splat({ graph, camera, warp, voxel_resolution, volume }: {
|
|
37
|
+
graph: any;
|
|
38
|
+
camera: any;
|
|
39
|
+
warp: any;
|
|
40
|
+
voxel_resolution: any;
|
|
41
|
+
volume: any;
|
|
42
|
+
}): {
|
|
43
|
+
extinction: any;
|
|
44
|
+
overflow: any;
|
|
45
|
+
dummy: any;
|
|
46
|
+
};
|
|
47
|
+
avboit_draw({ graph, view_ctx, camera, warp, integral, volumetrics_lut, volumetrics_metadata, accumulators }: {
|
|
48
|
+
graph: any;
|
|
49
|
+
view_ctx: any;
|
|
50
|
+
camera: any;
|
|
51
|
+
warp: any;
|
|
52
|
+
integral: any;
|
|
53
|
+
volumetrics_lut: any;
|
|
54
|
+
volumetrics_metadata: any;
|
|
55
|
+
accumulators: any;
|
|
56
|
+
}): {
|
|
57
|
+
color: any;
|
|
58
|
+
norm: any;
|
|
59
|
+
extinction: any;
|
|
60
|
+
emission: any;
|
|
61
|
+
};
|
|
62
|
+
/** Debug presentation only: called after shared resolve, never sampled by production optics. */
|
|
63
|
+
inspect(graph: any, view_ctx: any, output_resolution: any): number;
|
|
31
64
|
#private;
|
|
32
65
|
}
|
|
33
66
|
//# sourceMappingURL=GPUWaterRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GPUWaterRenderer.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/water/GPUWaterRenderer.js"],"names":[],"mappings":"AAaA
|
|
1
|
+
{"version":3,"file":"GPUWaterRenderer.d.ts","sourceRoot":"","sources":["../../../../../src/shade/renderer/water/GPUWaterRenderer.js"],"names":[],"mappings":"AAaA,sFAAsF;AACtF;IACI,gBAAc;IACd;;;;;;;;;MACiF;IAOjF,2BAEC;IAED,8FAA8F;IAC9F,qCAgBC;IAED,gBAKC;IAED;;;;;;;;;;;MA4GC;IAQD;;;;;YAMC;IAED;;;;;;;;;;MAOC;IAED;;;;;;;;;;;;;;MAwBC;IAED,gGAAgG;IAChG,mEAYC;;CA4BJ"}
|
|
@@ -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"}
|