summaryrefslogtreecommitdiff
path: root/src/sdf.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sdf.rs')
-rw-r--r--src/sdf.rs103
1 files changed, 80 insertions, 23 deletions
diff --git a/src/sdf.rs b/src/sdf.rs
index fee1a93..e7c78b8 100644
--- a/src/sdf.rs
+++ b/src/sdf.rs
@@ -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()
}
}