Skip to content

Commit

Permalink
add mandelbulb
Browse files Browse the repository at this point in the history
  • Loading branch information
altunenes committed May 5, 2024
1 parent 6d83853 commit 4587deb
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 71 deletions.
102 changes: 55 additions & 47 deletions shaders/mandelbulb.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ const AMBIENT: f32 = 0.2;
const SPECULAR_COEFF: f32 = 0.5;
const SHININESS: f32 = 1.0;
const EPS: vec3<f32> = vec3<f32>(0.001, 0.001, 0.001);

fn applyGamma(color: vec3<f32>, gamma: f32) -> vec3<f32> {
return pow(color, vec3<f32>(1.0 / gamma, 1.0 / gamma, 1.0 / gamma));
}
struct TimeUniform {
time: f32,
};
@group(1) @binding(0)
var<uniform> u_time: TimeUniform;

struct Params {
lambda: f32,
theta: f32,
Expand All @@ -36,30 +37,27 @@ struct Params {
};
@group(0) @binding(1)
var<uniform> params: Params;

fn mandelbulb(pos: vec3<f32>) -> f32 {
var z: vec3<f32> = pos;
var dr: f32 = 1.0;
var r: f32 = 0.0;
var zerg: f32 = POWER+params.iter;
for (var i: i32 = 0; i < MAX_STEPS; i = i + 1) {
r = length(z);
if (r > BAILOUT) {
break;
}

let theta: f32 = acos(z.z / r);
let phi: f32 = atan2(z.y, z.x);
dr = pow(r, POWER - 1.0) * POWER * dr + 1.0;

let zr: f32 = pow(r, POWER);
let newTheta: f32 = theta * POWER;
let newPhi: f32 = phi * POWER;
dr = pow(r, zerg - 1.0) * zerg * dr + 1.0;
let zr: f32 = pow(r, zerg);
let newTheta: f32 = theta * zerg;
let newPhi: f32 = phi * zerg;
z = zr * vec3<f32>(sin(newTheta) * cos(newPhi), sin(newPhi) * sin(newTheta), cos(newTheta));
z = z + pos;
}
return 0.5 * log(r) * r / dr;
}

fn normal(p: vec3<f32>) -> vec3<f32> {
let d: f32 = mandelbulb(p);
return normalize(vec3<f32>(
Expand All @@ -68,57 +66,67 @@ fn normal(p: vec3<f32>) -> vec3<f32> {
d - mandelbulb(p - vec3<f32>(0.0, 0.0, EPS.z))
));
}
fn colorize(d: f32, n: vec3<f32>, lightDir: vec3<f32>, time: f32) -> vec3<f32> {
let angle: f32 = dot(n, lightDir) * params.blue + params.bound;
let base: vec3<f32> = 0.5 + params.aa * cos(params.iter * vec3<f32>(1.0, 2.0, 3.0) * d + vec3<f32>(0.0, 0.5, 1.0) + time * vec3<f32>(0.3, 0.2, 0.1));
return mix(base, vec3<f32>(angle, angle * 0.5, angle * 0.25), 0.5);
fn colorize(pos: vec3<f32>, normal: vec3<f32>, dist: f32, time: f32) -> vec3<f32> {
let baseColor: vec3<f32> = vec3<f32>(0.3, 0.3, 0.3);
let iter_ratio: f32 = clamp(dist / 0.0, 1.0, 1.0);
let lenSq: f32 = length(pos);
let exteriorColor: vec3<f32> = vec3<f32>(0.0, 0.0, 0.0);
if (iter_ratio >= 1.0) {
let col1: vec3<f32> = 0.5 + params.sigma * sin(params.a + vec3<f32>(params.b, params.c, params.d) + PI * vec3<f32>(2.0 * lenSq) + time / 2.0);
let col2: vec3<f32> = 0.5 + params.blue * sin(1.5 + PI * vec3<f32>(lenSq) + time / 2.0);
return baseColor + 1.0 * sqrt(col1 * col2);
} else {
return mix(baseColor, exteriorColor, params.e);
}
}

fn rotateZ(p: vec3<f32>, a: f32) -> vec3<f32> {
let s: f32 = sin(a);
let c: f32 = cos(a);
return vec3<f32>(c * p.x - s * p.y, s * p.x + c * p.y, p.z);
}

fn rotateY(p: vec3<f32>, a: f32) -> vec3<f32> {
let s: f32 = sin(a);
let c: f32 = cos(a);
return vec3<f32>(c * p.x + s * p.z, p.y, -s * p.x + c * p.z);
}


@fragment
fn main(@builtin(position) FragCoord: vec4<f32>) -> @location(0) vec4<f32> {
let AA_LEVEL: i32 = i32(params.aa);
let resolution: vec2<f32> = vec2<f32>(1920.0, 1080.0);
let time: f32 = u_time.time * params.gamma;
let time: f32 = u_time.time * params.bound;
let camPos: vec3<f32> = rotateY(vec3<f32>(params.theta, params.alpha, -params.lambda), time);
var uv: vec2<f32> = (FragCoord.xy - 0.5 * resolution.xy) / resolution.y * vec2<f32>(2.0, 1.0);
var rayDir: vec3<f32> = normalize(vec3<f32>(uv, params.sigma));
rayDir = rotateZ(rayDir, sin(time) * 0.5);
rayDir = rotateY(rayDir, time);

var totalDist: f32 = 0.0;
for (var i: i32 = 0; i < MAX_STEPS; i = i + 1) {
let p: vec3<f32> = camPos + totalDist * rayDir;
let dist: f32 = mandelbulb(p);
totalDist += dist;
if (dist < SURFACE_DIST || totalDist > MAX_DIST) {
break;
var finalColor: vec3<f32> = vec3<f32>(0.0, 0.0, 0.0);
let totalSamples: f32 = f32(AA_LEVEL * AA_LEVEL);
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<f32> = (FragCoord.xy - 0.5 * resolution.xy) / resolution.y +
(vec2<f32>(f32(i), f32(j)) - 0.5 * vec2<f32>(f32(AA_LEVEL) - 1.0)) / resolution.y / f32(AA_LEVEL);
var rayDir: vec3<f32> = normalize(vec3<f32>(sampleUV, 2.0));
rayDir = rotateZ(rayDir, sin(time) * 0.5);
rayDir = rotateY(rayDir, time);
var totalDist: f32 = 0.0;
for (var k: i32 = 0; k < MAX_STEPS; k = k + 1) {
let p: vec3<f32> = camPos + totalDist * rayDir;
let dist: f32 = mandelbulb(p);
totalDist += dist;
if (dist < SURFACE_DIST || totalDist > MAX_DIST) {
break;
}
}
if (totalDist < MAX_DIST) {
let p: vec3<f32> = camPos + totalDist * rayDir;
let n: vec3<f32> = normal(p);
let lightDir: vec3<f32> = normalize(vec3<f32>(0.5, 1.0, -0.5));
let viewDir: vec3<f32> = normalize(-rayDir);
let reflectDir: vec3<f32> = reflect(-lightDir, n);
let diff: f32 = max(dot(n, lightDir), 0.0);
let spec: f32 = pow(max(dot(viewDir, reflectDir), 0.0), SHININESS);
let baseColor: vec3<f32> = colorize(p, n, totalDist, u_time.time);
finalColor += baseColor * (AMBIENT + diff + SPECULAR_COEFF * spec);
}
}
}

var color: vec3<f32> = vec3<f32>(0.0, 0.0, 0.0);
if (totalDist < MAX_DIST) {
let p: vec3<f32> = camPos + totalDist * rayDir;
let n: vec3<f32> = normal(p);
let lightDir: vec3<f32> = normalize(vec3<f32>(0.5, 1.0, -0.5));
let viewDir: vec3<f32> = normalize(-rayDir);
let reflectDir: vec3<f32> = reflect(-lightDir, n);
let diff: f32 = max(dot(n, lightDir), 0.0);
let spec: f32 = pow(max(dot(viewDir, reflectDir), 0.0), SHININESS);
let baseColor: vec3<f32> = colorize(totalDist, n, lightDir, u_time.time);
color = baseColor * (AMBIENT + diff + SPECULAR_COEFF * spec);
}

return vec4<f32>(color, 1.0);
}
finalColor = applyGamma(finalColor,params.gamma);
finalColor /= totalSamples;
return vec4<f32>(finalColor, 1.0);
}
46 changes: 23 additions & 23 deletions src/mandelbulb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,22 @@ 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, -15.00001..=15.0).text("l"));
ui.add(egui::Slider::new(&mut model.settings.theta, -15.0..=15.5).text("t"));
ui.add(egui::Slider::new(&mut model.settings.alpha, -15.5..=15.5).text("a"));
ui.add(egui::Slider::new(&mut model.settings.sigma, 0.0..=20.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.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"));
// ui.add(egui::Slider::new(&mut model.settings.d, -10.0..=20.0).text("e4"));
ui.add(egui::Slider::new(&mut model.settings.lambda, 0.0..=8.0).text("l"));
ui.add(egui::Slider::new(&mut model.settings.theta, -1.0..=1.0).text("t"));
ui.add(egui::Slider::new(&mut model.settings.alpha, -1.0..=1.0).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, 0.0..=2.0).text("g"));
ui.add(egui::Slider::new(&mut model.settings.blue, 0.0..=3.0).text("b"));
ui.add(egui::Slider::new(&mut model.settings.a, 0.0..=15.0).text("e1"));
ui.add(egui::Slider::new(&mut model.settings.b, 0.0..=1.0).text("r"));
ui.add(egui::Slider::new(&mut model.settings.c, 0.0..=1.0).text("g"));
ui.add(egui::Slider::new(&mut model.settings.d, 0.0..=1.0).text("b"));
// ui.add(egui::Slider::new(&mut model.settings.g, 1.0..=8.00).text("e5"));
//ui.add(egui::Slider::new(&mut model.settings.e, 0.002..=3.0).text("c1"));
ui.add(egui::Slider::new(&mut model.settings.e, 0.002..=3.0).text("c1"));
//ui.add(egui::Slider::new(&mut model.settings.f, 0.002..=3.0).text("c2"));
ui.add(egui::Slider::new(&mut model.settings.iter, 0.0..=5.0).text("iter"));
ui.add(egui::Slider::new(&mut model.settings.bound, 0.0..=5.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.iter, -10.0..=10.0).text("iter"));
ui.add(egui::Slider::new(&mut model.settings.bound, 0.0..=5.0).text("time"));
ui.add(egui::Slider::new(&mut model.settings.aa, 1.0..=4.0).text("AA"));
//ui.add(egui::Slider::new(&mut model.settings.tt, 1.0..=250.0).text("speed"));
});
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];
Expand Down Expand Up @@ -168,19 +168,19 @@ fn model(app: &App) -> Model {
lambda: 2.0,
theta:0.0,
alpha:0.0,
sigma:2.0,
gamma:0.25,
sigma:0.5,
gamma:0.5,
blue:0.5,
show_ui:true,
aa: 0.5,
iter:6.2831,
aa: 2.0,
iter:0.0,
bound:0.5,
tt:18.0,
a:0.1,
b:0.5,
c:1.0,
d:8.0,
e:2.0,
a:1.0,
b:0.0,
c:0.5,
d:1.0,
e:0.75,
f:2.0,
g:1.0,
};
Expand Down
2 changes: 1 addition & 1 deletion src/spiralimgwgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ fn model(app: &App) -> Model {
label: Some("time_bind_group_layout"),
});
let mut dummy_img = RgbaImage::new(800, 600);
dummy_img.put_pixel(0, 0, image::Rgba([255, 255, 255, 255])); // White pixel
dummy_img.put_pixel(0, 0, image::Rgba([255, 255, 255, 255]));
let texture = Texture::from_image(app, &image::DynamicImage::ImageRgba8(dummy_img));
let texture_view = texture.view().build();

Expand Down

0 comments on commit 4587deb

Please sign in to comment.