From 8b8a0c971bad98f85466f06a38bd3f2d30d24f22 Mon Sep 17 00:00:00 2001 From: altunenes Date: Thu, 23 May 2024 15:43:50 +0300 Subject: [PATCH] simple UI improvements --- shaders/expmandelbrotgpu.wgsl | 8 +-- shaders/mandelbulb.wgsl | 97 +++++++++++++++----------------- src/expmandelbrotgpu.rs | 102 ++++++++++++++++++++++++++++++---- src/mandelbulb.rs | 34 ++++++------ 4 files changed, 156 insertions(+), 85 deletions(-) diff --git a/shaders/expmandelbrotgpu.wgsl b/shaders/expmandelbrotgpu.wgsl index 6df3c59..f16d5ba 100644 --- a/shaders/expmandelbrotgpu.wgsl +++ b/shaders/expmandelbrotgpu.wgsl @@ -39,7 +39,7 @@ fn implicit(c: vec2, time: f32) -> vec2 { z.y = 2.0 * z.x * z.y + c.y; z.x = xnew; - let dampenedTime: f32 = time / params.tt; + let dampenedTime: f32 = time; z += 0.1 * vec2(sin(0.001 * dampenedTime), cos(0.001 * dampenedTime)); if (dot(z, z) > BOUND / 1.2) { @@ -55,15 +55,15 @@ fn main(@builtin(position) FragCoord: vec4) -> @location(0) vec4 { var BOUND: f32 = params.bound; var col: vec3 = vec3(0.0, 0.0, 0.0); let pan: vec2 = vec2(params.theta, params.alpha); - let zoomLevel: f32 = osc(params.lambda, params.lambda, 20.0, u_time.time / params.tt); + let zoomLevel: f32 = osc(params.lambda, params.lambda, 20.0, u_time.time * params.tt); let AA: i32 = i32(params.aa); let camSpeed: vec2 = vec2(0.0002, 0.0002); - let camPath: vec2 = vec2(sin(camSpeed.x * u_time.time / params.tt), cos(camSpeed.y * u_time.time / params.tt)); + let camPath: vec2 = vec2(sin(camSpeed.x), cos(camSpeed.y)); let resolution: vec2 = vec2(1920.0, 1080.0); for (var m: i32 = 0; m < AA; m = m + 1) { for (var n: i32 = 0; n < AA; n = n + 1) { let uv: vec2 = ((FragCoord.xy + vec2(f32(m), f32(n)) / f32(AA) - 0.5 * resolution) / min(resolution.y, resolution.x) * zoomLevel + pan + camPath) * 2.033 - vec2(2.14278); - let z_and_i: vec2 = implicit(uv, u_time.time); + let z_and_i: vec2 = implicit(uv, u_time.time* params.tt); let iter_ratio: f32 = z_and_i.x / f32(MAX_ITER); let lenSq: f32 = z_and_i.y; let exteriorColor: vec3 = params.a + params.b * sin(params.c + vec3(params.sigma, params.gamma, params.blue) + params.g*PI * vec3(params.d* iter_ratio) + u_time.time / params.e); diff --git a/shaders/mandelbulb.wgsl b/shaders/mandelbulb.wgsl index b790a45..6ac71aa 100644 --- a/shaders/mandelbulb.wgsl +++ b/shaders/mandelbulb.wgsl @@ -1,16 +1,13 @@ const PI: f32 = 3.141592653589793; -const MAX_STEPS: i32 = 150; +const MAX_STEPS: i32 = 250; const SURFACE_DIST: f32 = 0.001; -const MAX_DIST: f32 = 255.0; +const MAX_DIST: f32 = 150.0; const BAILOUT: f32 = 4.0; -const POWER: f32 = 8.0; const AMBIENT: f32 = 0.1; -const SPECULAR_COEFF: f32 = 1.1; -const SHININESS: f32 = 1.0; +const SPECULAR_COEFF: f32 = 0.5; +const SHININESS: f32 = 0.5; const EPS: vec3 = vec3(0.001, 0.001, 0.001); -fn applyGamma(color: vec3, gamma: f32) -> vec3 { - return pow(color, vec3(1.0 / gamma, 1.0 / gamma, 1.0 / gamma)); -} + struct TimeUniform { time: f32, }; @@ -52,7 +49,7 @@ fn osc(minValue: f32, maxValue: f32, interval: f32, pauseDuration: f32, currentT } } fn mandelbulb(pos: vec3, u_time: TimeUniform) -> f32 { - let dynamicPower: f32 = osc(params.iter, params.iter, 20.0, 5.0, u_time.time); + let power_osc: f32 = osc(params.iter, params.iter, 20.0, 5.0, u_time.time); var z: vec3 = pos; var dr: f32 = 1.0; var r: f32 = 0.0; @@ -66,13 +63,13 @@ fn mandelbulb(pos: vec3, u_time: TimeUniform) -> f32 { let phi: f32 = atan2(z.y, z.x); if (r < 1.0) { - dr = pow(r, dynamicPower - 1.0) * dynamicPower * dr + influence * 0.5; + dr = pow(r, power_osc - 1.0) * power_osc * dr + influence * 0.5; } else { - dr = pow(r, dynamicPower - 1.0) * dynamicPower * dr + influence; + dr = pow(r, power_osc - 1.0) * power_osc * dr + influence; } - let zr: f32 = pow(r, dynamicPower); - let newTheta: f32 = theta * dynamicPower; - let newPhi: f32 = phi * dynamicPower; + let zr: f32 = pow(r, power_osc); + let newTheta: f32 = theta * power_osc; + let newPhi: f32 = phi * power_osc; z = zr * vec3(sin(newTheta) * cos(newPhi), sin(newPhi) * sin(newTheta), cos(newTheta)); z += pos; @@ -91,41 +88,33 @@ fn normal(p: vec3, u_time: TimeUniform) -> vec3 { ); return normalize(n); } -fn curvatureColor(normal: vec3, pos: vec3, u_time: TimeUniform) -> vec3 { - let eps: f32 = osc(0.0001, 0.0001, 5.0, 0.0, u_time.time); - let n1 = normal(pos + vec3(eps, 0.0, 0.0), u_time); - let n2 = normal(pos - vec3(eps, 0.0, 0.0), u_time); - let curvature: f32 = length(n1 - n2) / (2.0 * eps); - return mix(vec3(0.5, 0.4, 0.3), vec3(1.0, 1.0, 0.8), curvature); -} -fn getBackground(uv: vec2) -> vec3 { - let topColor: vec3 = vec3(1.0, 0.9, 0.8); - let bottomColor: vec3 = vec3(0.2, 0.1, 0.0); - return mix(bottomColor, topColor, pow(uv.y * 0.5 + 0.5, 0.5)); + +fn bg(uv: vec2) -> vec3 { + let top: vec3 = vec3(1.0, 0.9, 0.8); + let bot: vec3 = vec3(0.9, 0.1, 0.0); + return mix(bot, top, pow(uv.y * 0.5 + 0.5, 0.5)); } fn colorize(pos: vec3, normal: vec3, dist: f32, viewDir: vec3, lightDir: vec3) -> vec3 { - let lightTone: vec3 = vec3(params.lambda, params.theta, params.alpha); - let middleTone: vec3 = vec3(params.sigma, params.gamma, params.blue); - let darkTone: vec3 = vec3(params.a, params.b, params.c); - + let first: vec3 = vec3(params.lambda, params.theta, params.alpha); + let mid: vec3 = vec3(params.sigma, params.gamma, params.blue); + let end: vec3 = vec3(params.a, params.b, params.c); let fresnel: f32 = pow(1.0 - max(dot(normal, viewDir), 0.0), 2.0); - let fresnelColor: vec3 = mix(lightTone, darkTone, fresnel); - + let fresnelc: vec3 = mix(first, end, fresnel); let depthHue: f32 = 0.5 + 0.5 * sin(dist * 1.1 + dot(normal, lightDir) * 0.5); - let depthColor: vec3 = mix(middleTone, darkTone, depthHue); + let depth: vec3 = mix(mid, end, depthHue); - let hueShift: f32 = atan2(pos.y, pos.x) * 0.015; - let colorShift: vec3 = vec3(sin(hueShift + 1.57), cos(hueShift + 1.57), sin(hueShift - 1.57)); - let vibrantColor: vec3 = vec3(0.7, 0.8, 0.1) + 0.1 * colorShift; + let hShif: f32 = atan2(pos.y, pos.x) * 0.15; + let shift: vec3 = vec3(sin(hShif + 1.57), cos(hShif + 1.57), sin(hShif - 1.57)); + let vC: vec3 = vec3(0.7, 1.0, 0.5) + 0.2 * shift; - let branchFactor: f32 = length(pos) % 5.0; - let branchColor: vec3 = vec3(params.d, params.e, params.f) * (0.3 + 0.45 * sin(branchFactor * 12.283185)); + let bran: f32 = length(pos) % 1.0; + let branC: vec3 = vec3(params.d, params.e, params.f) * (0.5 + 0.5 * sin(bran * 12.283185)); - var combinedColor: vec3 = mix(fresnelColor, depthColor, 0.1); - combinedColor = mix(combinedColor, vibrantColor, 0.3); + var combo: vec3 = mix(fresnelc, depth, 0.5); + combo = mix(combo, vC, 0.1); - return mix(combinedColor, branchColor, 0.5 + 0.5 * sin(branchFactor * 3.14159265)); + return mix(combo, branC, 0.5 + 1.0 * sin(bran * 3.14159265)); } fn rotateZ(p: vec3, a: f32) -> vec3 { @@ -140,7 +129,7 @@ fn rotateY(p: vec3, a: f32) -> vec3 { } -fn calculateLighting(n: vec3, lightDir: vec3, viewDir: vec3, reflectDir: vec3, u_time: TimeUniform) -> vec3 { +fn light(n: vec3, lightDir: vec3, viewDir: vec3, reflectDir: vec3, u_time: TimeUniform) -> vec3 { var diff: f32 = max(dot(n, lightDir), 0.2); let spec: f32 = pow(max(dot(viewDir, reflectDir), 0.0), SHININESS); let shadow: f32 = smoothstep(0.3, 1.0, diff); @@ -148,7 +137,7 @@ fn calculateLighting(n: vec3, lightDir: vec3, viewDir: vec3, refl let POWER2: f32 = osc(params.g, params.g, 10.0, 3.0, u_time.time); return vec3(POWER2) + diff + SPECULAR_COEFF * spec; } -fn dynamicRayMarch(ro: vec3, rd: vec3, minDist: f32, maxDist: f32, u_time: TimeUniform) -> f32 { +fn MARCH(ro: vec3, rd: vec3, minDist: f32, maxDist: f32, u_time: TimeUniform) -> f32 { var depth: f32 = 0.0; for (var i: i32 = 0; i < MAX_STEPS; i = i + 1) { let pos: vec3 = ro + rd * depth; @@ -163,13 +152,16 @@ fn dynamicRayMarch(ro: vec3, rd: vec3, minDist: f32, maxDist: f32, u_t } return maxDist; } -fn sharpenEffect(color: vec3, neighbor1: vec3, neighbor2: vec3) -> vec3 { +fn Sharp(color: vec3, neighbor1: vec3, neighbor2: vec3) -> vec3 { return color + 0.1 * (color - (neighbor1 + neighbor2) * 0.5); } -fn toneMapping(color: vec3) -> vec3 { +fn tone(color: vec3) -> vec3 { return color / (color + vec3(1.0)); } +fn applyGamma(color: vec3, gamma: f32) -> vec3 { + return pow(color, vec3(1.0 / gamma, 1.0 / gamma, 1.0 / gamma)); +} @fragment fn main(@builtin(position) FragCoord: vec4) -> @location(0) vec4 { let AA_LEVEL: i32 = i32(params.aa); @@ -178,17 +170,16 @@ fn main(@builtin(position) FragCoord: vec4) -> @location(0) vec4 { var finalColor: vec3 = vec3(0.0); var accumm: vec3 = vec3(0.0); var neighbor: i32 = 0; - let totalSamples: f32 = f32(AA_LEVEL * AA_LEVEL); - let backgroundColor: vec3 = getBackground(uv); - let power: f32 = osc2(-3.0, -5.0, 25.0, u_time.time); + let backgroundColor: vec3 = bg(uv); + let cameraaaa: f32 = osc2(-3.0, -5.0, 25.0, u_time.time); for (var i: i32 = 0; i < AA_LEVEL; i = i + 1) { for (var j: i32 = 0; j < AA_LEVEL; j = j + 1) { let sampleUV: vec2 = uv + (vec2(f32(i), f32(j)) - 0.5 * vec2(f32(AA_LEVEL) - 1.0)) / vec2(resolution.y, resolution.y) / f32(AA_LEVEL); - let camPos: vec3 = rotateY(vec3(0.0, 0.0, power), u_time.time * 0.25); + let camPos: vec3 = rotateY(vec3(0.0, 0.0, cameraaaa), u_time.time * 0.25); var rayDir: vec3 = normalize(vec3(sampleUV, 2.0)); rayDir = rotateZ(rayDir, sin(u_time.time * 0.25) * 1.5); rayDir = rotateY(rayDir, u_time.time * 0.25); - let totalDist: f32 = dynamicRayMarch(camPos, rayDir, SURFACE_DIST, MAX_DIST,u_time); + let totalDist: f32 = MARCH(camPos, rayDir, SURFACE_DIST, MAX_DIST,u_time); if (totalDist < MAX_DIST) { let p: vec3 = camPos + totalDist * rayDir; let n: vec3 = normal(p,u_time); @@ -196,7 +187,7 @@ fn main(@builtin(position) FragCoord: vec4) -> @location(0) vec4 { let viewDir: vec3 = normalize(-rayDir); let reflectDir: vec3 = reflect(-lightDir, n); let color: vec3 = colorize(p, n, totalDist, viewDir, lightDir); - let lightEffect: vec3 = calculateLighting(n, lightDir, viewDir, reflectDir,u_time); + let lightEffect: vec3 = light(n, lightDir, viewDir, reflectDir,u_time); finalColor += color * lightEffect; accumm += color; neighbor += 1; @@ -207,9 +198,9 @@ fn main(@builtin(position) FragCoord: vec4) -> @location(0) vec4 { } if (neighbor > 1) { - finalColor = sharpenEffect(finalColor, accumm / f32(neighbor), finalColor / f32(neighbor)); + finalColor = Sharp(finalColor, accumm / f32(neighbor), finalColor / f32(neighbor)); } - finalColor = toneMapping(finalColor); - finalColor = applyGamma(finalColor, 0.5); + finalColor = tone(finalColor); + finalColor = applyGamma(finalColor, 0.5); return vec4(finalColor, 1.0); } \ No newline at end of file diff --git a/src/expmandelbrotgpu.rs b/src/expmandelbrotgpu.rs index 3fc94f7..5f6c69a 100644 --- a/src/expmandelbrotgpu.rs +++ b/src/expmandelbrotgpu.rs @@ -49,6 +49,8 @@ fn main() { .run(); } fn update(app: &App, model: &mut Model, update: Update) { + static mut REVERSE_COLORS: bool = false; + let egui = &mut model.egui; egui.set_elapsed_time(update.since_start); let ctx = egui.begin_frame(); @@ -56,12 +58,56 @@ fn update(app: &App, model: &mut Model, update: Update) { model.settings.show_ui = !model.settings.show_ui; } egui::Window::new("Shader Settings").show(&ctx, |ui| { - ui.add(egui::Slider::new(&mut model.settings.lambda, 0.00001..=2.0).text("l")); - ui.add(egui::Slider::new(&mut model.settings.theta, 0.0..=1.5).text("t")); - ui.add(egui::Slider::new(&mut model.settings.alpha, -0.5..=0.5).text("a")); - ui.add(egui::Slider::new(&mut model.settings.sigma, 0.0..=2.0).text("r")); - ui.add(egui::Slider::new(&mut model.settings.gamma, -1.0..=2.0).text("g")); - ui.add(egui::Slider::new(&mut model.settings.blue, 0.0..=2.0).text("b")); + ui.horizontal(|ui| { + ui.add(egui::Slider::new(&mut model.settings.lambda, 0.00001..=2.0).text("zoom")); + if ui.button("-").clicked() { + model.settings.lambda -= 0.00001; + if model.settings.lambda < 0.00001 { + model.settings.lambda = 0.00001; + } + } + if ui.button("+").clicked() { + model.settings.lambda += 0.00001; + if model.settings.lambda > 2.0 { + model.settings.lambda = 2.0; + } + } + }); + + ui.horizontal(|ui| { + ui.add(egui::Slider::new(&mut model.settings.theta, 0.0..=1.5).text("x_axis")); + if ui.button("-").clicked() { + model.settings.theta -= 0.0001; + if model.settings.theta < 0.0 { + model.settings.theta = 0.0; + } + } + if ui.button("+").clicked() { + model.settings.theta += 0.0001; + if model.settings.theta > 1.5 { + model.settings.theta = 1.5; + } + } + }); + + ui.horizontal(|ui| { + ui.add(egui::Slider::new(&mut model.settings.alpha, -0.5..=0.5).text("y_axis")); + if ui.button("-").clicked() { + model.settings.alpha -= 0.0001; + if model.settings.alpha < -0.5 { + model.settings.alpha = -0.5; + } + } + if ui.button("+").clicked() { + model.settings.alpha += 0.0001; + if model.settings.alpha > 0.5 { + model.settings.alpha = 0.5; + } + } + }); + ui.add(egui::Slider::new(&mut model.settings.sigma, 0.0..=4.0).text("R")); + ui.add(egui::Slider::new(&mut model.settings.gamma, 0.0..=4.0).text("G")); + ui.add(egui::Slider::new(&mut model.settings.blue, 0.0..=4.0).text("B")); ui.add(egui::Slider::new(&mut model.settings.a, -10.0..=10.5).text("e1")); ui.add(egui::Slider::new(&mut model.settings.b, -10.0..=10.5).text("e2")); ui.add(egui::Slider::new(&mut model.settings.c, -10.0..=10.0).text("e3")); @@ -71,10 +117,44 @@ fn update(app: &App, model: &mut Model, update: Update) { ui.add(egui::Slider::new(&mut model.settings.f, 0.002..=3.0).text("c2")); ui.add(egui::Slider::new(&mut model.settings.iter, 1.0..=2000.0).text("iter")); ui.add(egui::Slider::new(&mut model.settings.bound, 1.0..=2000.0).text("bound")); - ui.add(egui::Slider::new(&mut model.settings.aa, 0.0..=10.0).text("AA")); - ui.add(egui::Slider::new(&mut model.settings.tt, 1.0..=250.0).text("speed")); + ui.add(egui::Slider::new(&mut model.settings.aa, 0.0..=10.0).text("smart AA")); + ui.add(egui::Slider::new(&mut model.settings.tt, 0.0..=1.0).text("time")); + if ui.button("alternative view").clicked() { + unsafe { + REVERSE_COLORS = !REVERSE_COLORS; + if REVERSE_COLORS { + model.settings.iter = 350.0; + model.settings.bound = 50.0; + model.settings.a = -0.5; + model.settings.b = 0.0; + model.settings.c = 0.0; + model.settings.d = 2.0; + } else { + model.settings.iter = 855.0; + model.settings.bound = 3.5; + model.settings.a = 0.1; + model.settings.b = 0.5; + model.settings.c = 1.0; + model.settings.d = 8.0; + } + } + } + ui.horizontal(|ui| { + if ui.button("Hide UI").clicked() { + model.settings.show_ui = false; + } + ui.label("Press H to revert"); + }); }); - let params_data = [model.settings.lambda, model.settings.theta,model.settings.alpha, model.settings.sigma,model.settings.gamma,model.settings.blue,model.settings.aa,model.settings.iter,model.settings.bound,model.settings.tt,model.settings.a,model.settings.b,model.settings.c,model.settings.d,model.settings.e,model.settings.f,model.settings.g]; + + let params_data = [ + model.settings.lambda, model.settings.theta, model.settings.alpha, + model.settings.sigma, model.settings.gamma, model.settings.blue, + model.settings.aa, model.settings.iter, model.settings.bound, + model.settings.tt, model.settings.a, model.settings.b, + model.settings.c, model.settings.d, model.settings.e, + model.settings.f, model.settings.g + ]; let params_bytes = bytemuck::cast_slice(¶ms_data); app.main_window().queue().write_buffer(&model.params_uniform, 0, ¶ms_bytes); } @@ -172,10 +252,10 @@ fn model(app: &App) -> Model { gamma:0.5, blue:1.0, show_ui:true, - aa: 4.0, + aa: 2.0, iter:855.0, bound:3.5, - tt:18.0, + tt:0.1, a:0.1, b:0.5, c:1.0, diff --git a/src/mandelbulb.rs b/src/mandelbulb.rs index 3bf590e..6d2173e 100644 --- a/src/mandelbulb.rs +++ b/src/mandelbulb.rs @@ -165,24 +165,24 @@ fn model(app: &App) -> Model { label: Some("time_bind_group"), }); let settings = Settings { - lambda: 2.0, - theta:0.9, - alpha:0.85, - sigma:0.75, - gamma:0.7, - blue:0.65, - show_ui:true, + lambda: 0.8, + theta: 1.0, + alpha: 0.7, + sigma: 0.3, + gamma: 0.7, + blue: 0.3, + show_ui: true, aa: 2.0, - iter:8.0, - bound:5.05, - tt:0.0001, - a:1.7, - b:1.7, - c:0.1, - d:2.0, - e:3.0, - f:0.7, - g:0.1, + iter: 8.0, + bound: 5.05, + tt: 0.0001, + a: 0.1, + b: 0.4, + c: 0.1, + d: 0.4, + e: 0.2, + f: 0.0, + g: 0.1, }; let params_data = [settings.lambda, settings.theta, settings.alpha,settings.sigma,settings.gamma,settings.blue,settings.aa,settings.iter,settings.bound,settings.tt,settings.a,settings.b,settings.c,settings.d,settings.e,settings.f,settings.g]; let params_bytes = bytemuck::cast_slice(¶ms_data);