diff options
Diffstat (limited to 'src/sdf.rs')
-rw-r--r-- | src/sdf.rs | 103 |
1 files changed, 80 insertions, 23 deletions
@@ -12,6 +12,7 @@ macro_rules! write_str { pub enum Constant { F32(f32), Time(f32, f32), + // @TODO: sin, sqrt, mod } impl From<f32> for Constant { @@ -32,6 +33,12 @@ impl Constant { pub struct Constant3(Constant, Constant, Constant); +impl From<(Constant, Constant, Constant)> for Constant3 { + fn from(x: (Constant, Constant, Constant)) -> Self { + Self(x.0, x.1, x.2) + } +} + impl Constant3 { fn to_glsl(&self) -> String { format!( @@ -45,23 +52,39 @@ impl Constant3 { pub enum R3ToR3 { Identity, + Compose(Box<R3ToR3>, Box<R3ToR3>), Translate(Constant3), + Sin(Constant), + //@TODO InfiniteMirrors(f32) } pub enum RToR { Identity, + Compose(Box<RToR>, Box<RToR>), Add(Constant), } pub enum R3ToR { Sphere(Constant), Cube(Constant), - PrePost(Box<R3ToR3>, Box<R3ToR>, Box<RToR>), + Compose(Box<R3ToR3>, Box<R3ToR>, Box<RToR>), Mix(Box<R3ToR>, Box<R3ToR>, Constant), SmoothMin(Box<R3ToR>, Box<R3ToR>), Min(Box<R3ToR>, Box<R3ToR>), } +impl R3ToR3 { + pub fn compose(self, b: Self) -> Self { + Self::Compose(Box::new(self), Box::new(b)) + } +} + +impl RToR { + pub fn compose(self, b: Self) -> Self { + Self::Compose(Box::new(self), Box::new(b)) + } +} + impl R3ToR { pub fn sphere_f32(r: f32) -> Self { Self::Sphere(r.into()) @@ -86,6 +109,10 @@ impl R3ToR { pub fn smooth_min(a: Self, b: Self) -> Self { Self::SmoothMin(Box::new(a), Box::new(b)) } + + pub fn compose(pre: R3ToR3, f: Self, post: RToR) -> Self { + Self::Compose(Box::new(pre), Box::new(f), Box::new(post)) + } } #[derive(Clone, Copy)] @@ -136,17 +163,22 @@ impl Function for RToR { use RToR::*; match self { - Identity => return input, + Identity => input, Add(x) => { + let output = var.next(); write_str!( code, - "float {} = {input} + {};\n", - var.next(), + "float {output} = {input} + {};\n", x.to_glsl() ); + output } + Compose(a, b) => { + let a_output = a.to_glsl(input, code, var); + let b_output = b.to_glsl(a_output, code, var); + b_output + }, } - var.prev() } } @@ -155,18 +187,34 @@ impl Function for R3ToR3 { use R3ToR3::*; match self { - Identity => return input, + Identity => input, Translate(by) => { + let output = var.next(); write_str!( code, - "vec3 {} = {input} + {};\n", - var.next(), + "vec3 {output} = {input} + {};\n", by.to_glsl() ); + output + } + Sin(c) => { + // we shouldn't just do sin(c x), since that + // would multiply the derivative by c (which breaks the SDF if c > 1) + // so we'll do sin(c x) / c instead. + let c = c.to_glsl(); + let output = var.next(); + write_str!( + code, + "vec3 {output} = sin({c} * {input}) * (1.0 / {c});\n" + ); + output + }, + Compose(a, b) => { + let a_output = a.to_glsl(input, code, var); + let b_output = b.to_glsl(a_output, code, var); + b_output } } - - var.prev() } } @@ -178,54 +226,63 @@ impl Function for R3ToR { // these SDFs. Sphere(r) => { let r = r.to_glsl(); - write_str!(code, "float {} = length({input}) - {r};\n", var.next()); + let output = var.next(); + write_str!(code, "float {output} = length({input}) - {r};\n"); + output } Cube(r) => { let r = r.to_glsl(); let q = var.next(); write_str!(code, "vec3 {q} = abs({input}) - {r};\n"); + let output = var.next(); write_str!( code, - "float {} = length(max({q},0.0)) + min(max({q}.x,max({q}.y,{q}.z)),0.0);\n", - var.next() - ) + "float {output} = length(max({q},0.0)) + min(max({q}.x,max({q}.y,{q}.z)),0.0);\n" + ); + output } Mix(a, b, t) => { let t = t.to_glsl(); let a_output = a.to_glsl(input, code, var); let b_output = b.to_glsl(input, code, var); + let output = var.next(); write_str!( code, - "float {} = mix({a_output}, {b_output}, clamp({t}, 0.0, 1.0));\n", - var.next() + "float {output} = mix({a_output}, {b_output}, clamp({t}, 0.0, 1.0));\n" ); + output } Min(a, b) => { let a_output = a.to_glsl(input, code, var); let b_output = b.to_glsl(input, code, var); + let output = var.next(); write_str!( code, - "float {} = min({a_output}, {b_output});\n", - var.next() + "float {output} = min({a_output}, {b_output});\n" ); + output }, SmoothMin(a, b) => { let a_output = a.to_glsl(input, code, var); let b_output = b.to_glsl(input, code, var); + let output = var.next(); // for now we're using a fixed k value // i don't want to make this a Constant right now, // since most values of k (i.e. <0, >1) look bad/just like min. let k = 0.2; write_str!( code, - "float {} = sdf_smooth_min({a_output}, {b_output}, {k});\n", - var.next() + "float {output} = sdf_smooth_min({a_output}, {b_output}, {k});\n" ); + output + }, + Compose(pre, f, post) => { + let pre_output = pre.to_glsl(input, code, var); + let f_output = f.to_glsl(pre_output, code, var); + let post_output = post.to_glsl(f_output, code, var); + post_output }, - _ => todo!(), } - - var.prev() } } |