From f019024fcee55ecbc170e6eb289b04dda219401a Mon Sep 17 00:00:00 2001 From: Niklas Korz Date: Wed, 22 Sep 2021 13:42:02 +0200 Subject: [PATCH] Ray paths for outline of high exponent area --- src/functions.rs | 8 +-- src/main_view.rs | 55 +++++++++++++++++++- src/main_view.wgsl | 123 +++++++++++++++++++++++++++++++++++++-------- src/overlay.wgsl | 13 ++++- 4 files changed, 171 insertions(+), 28 deletions(-) diff --git a/src/functions.rs b/src/functions.rs index 48cfa31..e18ce97 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -50,9 +50,9 @@ let t_out = part_out * t_env + (1.0 - part_out) * t_src; return refraction(t_in, t_out, v, normal);" .to_string(), Self::MiragePlane => "let t_env = 15.0; // °C -let t_src = 22.0; // °C +let t_src = 30.0; // °C let max_dist = 0.01; -let plane_p0 = vec3(0.0, 0.0, 0.0); +let plane_p0 = vec3(0.0, 0.1, 0.0); let plane_n = vec3(0.0, 1.0, 0.0); let dist_in = point_plane_distance(p_prev, plane_n, plane_p0); @@ -81,9 +81,9 @@ let t_out = part_out * t_env + (1.0 - part_out) * t_src; return refraction(t_in, t_out, v, normal);" .to_string(), Self::MiragePlaneSigmoid => "let t_env = 15.0; // °C -let t_src = 22.0; // °C +let t_src = 30.0; // °C let max_dist = 0.01; -let plane_p0 = vec3(0.0, 0.0, 0.0); +let plane_p0 = vec3(0.0, 0.1, 0.0); let plane_n = vec3(0.0, 1.0, 0.0); let dist_in = point_plane_distance(p_prev, plane_n, plane_p0); diff --git a/src/main_view.rs b/src/main_view.rs index 301d125..c3121cb 100644 --- a/src/main_view.rs +++ b/src/main_view.rs @@ -67,6 +67,7 @@ pub struct MainView { overlay_bind_group: wgpu::BindGroup, overlay_pipeline: wgpu::ComputePipeline, settings_buffer: wgpu::Buffer, + exponents_buffer: wgpu::Buffer, camera_buffer: wgpu::Buffer, camera: ArcballCamera, prev_pointer_pos: Option<(f32, f32)>, @@ -135,6 +136,13 @@ impl MainView { usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, }); + let exponents_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("exponents_buffer"), + size: 4 * (width as u64) * (height as u64), + usage: wgpu::BufferUsages::STORAGE, + mapped_at_creation: false, + }); + let mut camera = ArcballCamera::new(center, 1.0, [width as f32, height as f32]); camera.zoom(-1.0, 1.0); let camera_uniform = CameraUniform::moving(&camera); @@ -187,6 +195,16 @@ impl MainView { }, count: None, }, + wgpu::BindGroupLayoutEntry { + binding: 4, + visibility: wgpu::ShaderStages::COMPUTE, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, ], label: Some("compute_bind_group_layout"), }); @@ -209,6 +227,10 @@ impl MainView { binding: 3, resource: settings_buffer.as_entire_binding(), }, + wgpu::BindGroupEntry { + binding: 4, + resource: exponents_buffer.as_entire_binding(), + }, ], label: Some("compute_bind_group"), }); @@ -339,6 +361,16 @@ impl MainView { }, count: None, }, + wgpu::BindGroupLayoutEntry { + binding: 4, + visibility: wgpu::ShaderStages::COMPUTE, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, ], label: Some("overlay_bind_group_layout"), }); @@ -361,6 +393,10 @@ impl MainView { binding: 3, resource: settings_buffer.as_entire_binding(), }, + wgpu::BindGroupEntry { + binding: 4, + resource: exponents_buffer.as_entire_binding(), + }, ], label: Some("overlay_bind_group"), }); @@ -398,6 +434,7 @@ impl MainView { overlay_bind_group, overlay_pipeline, settings_buffer, + exponents_buffer, camera_buffer, camera, @@ -529,6 +566,13 @@ impl MainView { wgpu::TextureFormat::Rgba32Float, true, ); + self.exponents_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("exponents_buffer"), + size: 4 * (width as u64) * (height as u64), + usage: wgpu::BufferUsages::STORAGE, + mapped_at_creation: false, + }); + self.compute_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &self.compute_bind_group_layout, entries: &[ @@ -548,6 +592,10 @@ impl MainView { binding: 3, resource: self.settings_buffer.as_entire_binding(), }, + wgpu::BindGroupEntry { + binding: 4, + resource: self.exponents_buffer.as_entire_binding(), + }, ], label: Some("compute_bind_group"), }); @@ -570,6 +618,10 @@ impl MainView { binding: 3, resource: self.settings_buffer.as_entire_binding(), }, + wgpu::BindGroupEntry { + binding: 4, + resource: self.exponents_buffer.as_entire_binding(), + }, ], label: Some("overlay_bind_group"), }); @@ -673,8 +725,7 @@ impl MainView { let original_shader_src = self.shader_src.clone(); let high_accuracy_shader_src = self .shader_src - .replace("let h_initial: f32 = 0.1;", "let h_initial: f32 = 0.001;") - .replace("let steps: i32 = 100;", "let steps: i32 = 5000;"); + .replace("let h_initial = 0.1;", "let h_initial = 0.001;"); self.reload_shader( device, Some(&high_accuracy_shader_src), diff --git a/src/main_view.wgsl b/src/main_view.wgsl index f23155b..0b3843d 100644 --- a/src/main_view.wgsl +++ b/src/main_view.wgsl @@ -26,6 +26,13 @@ struct Settings { [[group(0), binding(3)]] var settings: Settings; +[[block]] +struct Exponents { + data: array; +}; +[[group(0), binding(4)]] +var exponents: Exponents; + struct Vertex { x: f32; y: f32; @@ -218,9 +225,6 @@ fn ray_color(origin: vec3, direction: vec3, max_dist: f32) -> vec4(0.0, 0.0, 0.0, 0.0); } -let h_initial: f32 = 0.1; -let steps: i32 = 5000; - struct NonlinearRayColorResult { color: vec4; mapping_point: vec4; @@ -238,6 +242,7 @@ fn nonlinear_ray_color(start_point: vec3, start_dir: vec3) -> Nonlinea var t: f32 = 0.0; var last_v: vec3 = vec3(0.0, 0.0, 0.0); var last_diff: f32 = -1.0; + let h_initial = 0.1; var h: f32 = h_initial; for (; t <= 5.0;) { @@ -283,31 +288,24 @@ fn sample_rays(start_point: vec3, start_dir: vec3, samples_index: i32, var cur_dir: vec3 = start_dir; var color: vec4; var t: f32 = 0.0; - var last_v: vec3 = vec3(0.0, 0.0, 0.0); - var last_diff: f32 = -1.0; - var h: f32 = h_initial; + let h = 0.001; + let steps: i32 = 5000; var sample: RaySample; sample.color = vec4(sample_color, 0.5); let sample_steps = 100; let sample_step_size = steps / sample_steps; - for (var i: i32 = 0; i < steps && t <= 5.0; i = i + 1) { + for (var i: i32 = 0; i < steps; i = i + 1) { // Runge-Kutta method let k1 = field_function(cur_point, cur_point, start_dir, cur_dir, t); let k2 = field_function(cur_point, cur_point + 0.5 * h * k1, start_dir, k1, t + 0.5 * h); let k3 = field_function(cur_point, cur_point + 0.5 * h * k2, start_dir, k2, t + 0.5 * h); let k4 = field_function(cur_point, cur_point + h * k3, start_dir, k3, t + h); let v = (k1 + 2.0 * k2 + 2.0 * k3 + k4) / 6.0; - let diff = length(v - last_v); - if (last_diff >= 0.0 && diff > 10.0 * last_diff && h > 0.002) { - h = 0.001; - continue; - } cur_dir = (1.0 - field_weight) * cur_dir + field_weight * v; let step_dir = cur_dir * h; - if (i % sample_step_size == 0) { sample.position = vec4(cur_point, 1.0); let index = samples_index * sample_steps + i / sample_step_size; @@ -316,11 +314,6 @@ fn sample_rays(start_point: vec3, start_dir: vec3, samples_index: i32, cur_point = cur_point + step_dir; t = t + h; - last_v = v; - if (2.0 * diff < last_diff && h < h_initial) { - h = h_initial; - } - last_diff = diff; } } @@ -386,8 +379,98 @@ fn main_view([[builtin(global_invocation_id)]] gid: vec3) { // Sample points for reference view // Only executed in first workgroup for best performance if (gid.x < 8u && gid.y == 0u) { - let mouse_pos = vec2(settings.mouse_pos_x, settings.mouse_pos_y); - let pos = mouse_pos + 0.01 * sample_positions[i32(gid.x)]; + //let mouse_pos = vec2(settings.mouse_pos_x, settings.mouse_pos_y); + //let pos = mouse_pos + 0.01 * sample_positions[i32(gid.x)]; + + let min_exp = 0.8; + var pos: vec2 = vec2(0.0, 0.0); + var found: bool = false; + var sum: i32 = 0; + if (gid.x == 0u) { + // Bottom left + for (var x: i32 = 0; x < size.x; x = x + 1) { + for (var y: i32 = 0; y < size.y; y = y + 1) { + if (exponents.data[y * size.y + x] >= min_exp && (size.x - x) + y >= sum) { + pos = vec2(f32(x), f32(y)); + sum = (size.x - x) + y; + } + } + } + } elseif (gid.x == 1u) { + // Bottom middle + for (var y: i32 = size.x - 1; y >= 0 && !found; y = y - 1) { + for (var x: i32 = 0; x < size.x && !found; x = x + 1) { + if (exponents.data[y * size.y + x] >= min_exp) { + pos = vec2(f32(x), f32(y)); + found = true; + } + } + } + } elseif (gid.x == 2u) { + // Bottom right + for (var x: i32 = 0; x < size.x; x = x + 1) { + for (var y: i32 = 0; y < size.y; y = y + 1) { + if (exponents.data[y * size.y + x] >= min_exp && x + y >= sum) { + pos = vec2(f32(x), f32(y)); + sum = x + y; + } + } + } + } elseif (gid.x == 3u) { + // Middle right + for (var x: i32 = size.x - 1; x >= 0 && !found; x = x - 1) { + for (var y: i32 = 0; y < size.y && !found; y = y + 1) { + if (exponents.data[y * size.y + x] >= min_exp) { + pos = vec2(f32(x), f32(y)); + found = true; + } + } + } + } elseif (gid.x == 4u) { + // Top right + for (var x: i32 = 0; x < size.x; x = x + 1) { + for (var y: i32 = 0; y < size.y; y = y + 1) { + if (exponents.data[y * size.y + x] >= min_exp && x + (size.y - y) >= sum) { + pos = vec2(f32(x), f32(y)); + sum = x + (size.y - y); + } + } + } + } elseif (gid.x == 5u) { + // Top middle + for (var y: i32 = 0; y < size.y && !found; y = y + 1) { + for (var x: i32 = 0; x < size.x && !found; x = x + 1) { + if (exponents.data[y * size.y + x] >= min_exp) { + pos = vec2(f32(x), f32(y)); + found = true; + } + } + } + } elseif (gid.x == 6u) { + // Top left + for (var x: i32 = 0; x < size.x; x = x + 1) { + for (var y: i32 = 0; y < size.y; y = y + 1) { + if (exponents.data[y * size.y + x] >= min_exp && (size.x - x) + (size.y - y) >= sum) { + pos = vec2(f32(x), f32(y)); + sum = (size.x - x) + (size.y - y); + } + } + } + } elseif (gid.x == 7u) { + // Middle left + for (var x: i32 = 0; x < size.x && !found; x = x + 1) { + for (var y: i32 = 0; y < size.y && !found; y = y + 1) { + if (exponents.data[y * size.y + x] >= min_exp) { + pos = vec2(f32(x), f32(y)); + found = true; + } + } + } + } + + pos.x = pos.x / (width - 1.0); + pos.y = (height - 1.0 - pos.y) / (height - 1.0); + let color = sample_colors[i32(gid.x)]; let u2 = pos.x * viewport_width - 0.5 * viewport_width; let v2 = pos.y * viewport_height - 0.5 * viewport_height; diff --git a/src/overlay.wgsl b/src/overlay.wgsl index 9b05ebf..2a58102 100644 --- a/src/overlay.wgsl +++ b/src/overlay.wgsl @@ -91,6 +91,13 @@ struct Settings { [[group(0), binding(3)]] var settings: Settings; +[[block]] +struct Exponents { + data: array; +}; +[[group(0), binding(4)]] +var exponents: Exponents; + fn lyapunov_exponent(coords: vec2) -> f32 { let x_next = textureLoad(mapping, coords + vec2(settings.central_difference_delta, 0), 0).xyz; let x_prev = textureLoad(mapping, coords - vec2(settings.central_difference_delta, 0), 0).xyz; @@ -120,8 +127,10 @@ fn overlay(coords: vec2, size: vec2) -> vec4 { if (settings.overlay_mode == 1) { let exponent = lyapunov_exponent(coords); let scaled_exponent = exp(settings.lyapunov_scaling * exponent - 5.0); - if (scaled_exponent > 0.8) { - return scaled_exponent * vec4(1.0, 1.0, 1.0, 1.0) + (1.0 - scaled_exponent) * color; + exponents.data[size.y * coords.y + coords.x] = scaled_exponent; + if (scaled_exponent >= 0.8) { + let alpha = min(1.0, scaled_exponent) * 0.5; + return alpha * vec4(1.0, 1.0, 1.0, 1.0) + (1.0 - alpha) * color; } } return color; -- 2.51.2