Skip to content

Instantly share code, notes, and snippets.

@lachlansneff
Created February 17, 2021 06:21
Show Gist options
  • Save lachlansneff/c19177d65cc57a6c0d844a0d159407ba to your computer and use it in GitHub Desktop.
Save lachlansneff/c19177d65cc57a6c0d844a0d159407ba to your computer and use it in GitHub Desktop.
use std::ops::{Add, Sub, SubAssign, Mul, Div, Neg, BitOr, BitOrAssign, BitAnd, BitAndAssign};
use std::mem;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum Op {
Const(f32),
X,
Y,
Z,
Add(Arc<Op>, Arc<Op>),
Sub(Arc<Op>, Arc<Op>),
Mul(Arc<Op>, Arc<Op>),
Div(Arc<Op>, Arc<Op>),
Abs(Arc<Op>),
Neg(Arc<Op>),
Sqrt(Arc<Op>),
Squared(Arc<Op>),
Pow(Arc<Op>, i32),
Max(Arc<Op>, Arc<Op>),
Min(Arc<Op>, Arc<Op>),
Remap {
x: Arc<Op>,
y: Arc<Op>,
z: Arc<Op>,
op: Arc<Op>,
}
}
pub fn slow_sdf(p: (f32, f32, f32), op: &Op) -> f32 {
match op {
Op::Const(x) => *x,
Op::X => p.0,
Op::Y => p.1,
Op::Z => p.2,
Op::Add(a, b) => slow_sdf(p, &a) + slow_sdf(p, &b),
Op::Sub(a, b) => slow_sdf(p, &a) - slow_sdf(p, &b),
Op::Mul(a, b) => slow_sdf(p, &a) * slow_sdf(p, &b),
Op::Div(a, b) => slow_sdf(p, &a) / slow_sdf(p, &b),
Op::Abs(x) => slow_sdf(p, x).abs(),
Op::Neg(x) => -slow_sdf(p, x),
Op::Sqrt(x) => slow_sdf(p, x).sqrt(),
Op::Squared(x) => slow_sdf(p, x).powi(2),
Op::Pow(x, exp) => slow_sdf(p, x).powi(*exp),
Op::Max(a, b) => slow_sdf(p, &a).max(slow_sdf(p, &b)),
Op::Min(a, b) => slow_sdf(p, &a).min(slow_sdf(p, &b)),
Op::Remap { x, y, z, op } => slow_sdf((slow_sdf(p, &x), slow_sdf(p, &y), slow_sdf(p, &z)), &op),
}
}
impl Op {
pub fn abs(self) -> Self {
match self {
Op::Abs(x) => Op::Abs(x),
Op::Squared(x) => Op::Squared(x),
x => Op::Abs(Arc::new(x))
}
}
pub fn sqrt(self) -> Self {
Op::Sqrt(Arc::new(self))
}
pub fn pow(self, exp: i32) -> Self {
if exp == 1 {
self
} else if exp == 2 {
Self::Squared(Arc::new(self))
} else {
Self::Pow(Arc::new(self), exp)
}
}
pub fn max(self, rhs: Self) -> Self {
Op::Max(Arc::new(self), Arc::new(rhs))
}
pub fn min(self, rhs: Self) -> Self {
Op::Min(Arc::new(self), Arc::new(rhs))
}
pub fn remap(self, x: Self, y: Self, z: Self) -> Self {
Op::Remap {
x: Arc::new(x),
y: Arc::new(y),
z: Arc::new(z),
op: Arc::new(self),
}
}
}
impl Add<Self> for Op {
type Output = Self;
fn add(self, other: Self) -> Self {
match (self, other) {
(Op::Const(a), Op::Const(b)) => Op::Const(a + b),
(x, Op::Const(y)) if y == 0.0 => x,
(x, Op::Neg(y)) => Op::Sub(Arc::new(x), y),
(a, b) => Op::Add(Arc::new(a), Arc::new(b)),
}
}
}
impl Add<f32> for Op {
type Output = Self;
fn add(self, other: f32) -> Self {
match self {
Op::Const(x) => Op::Const(x + other),
x if other == 0.0 => x,
x => Op::Add(Arc::new(x), Arc::new(Op::Const(other))),
}
}
}
impl Sub<Self> for Op {
type Output = Self;
fn sub(self, other: Self) -> Self {
match (self, other) {
(Op::Const(a), Op::Const(b)) => Op::Const(a - b),
(x, Op::Const(y)) if y == 0.0 => x,
(x, Op::Neg(y)) => Op::Add(Arc::new(x), y),
(a, b) => Op::Sub(Arc::new(a), Arc::new(b)),
}
}
}
impl Sub<f32> for Op {
type Output = Self;
fn sub(self, other: f32) -> Self {
match self {
Op::Const(x) => Op::Const(x - other),
x if other == 0.0 => x,
x => Op::Sub(Arc::new(x), Arc::new(Op::Const(other))),
}
}
}
impl Mul<Self> for Op {
type Output = Self;
fn mul(self, other: Self) -> Self {
match (self, other) {
(Op::Const(a), Op::Const(b)) => Op::Const(a * b),
(x, Op::Const(y)) if y == 1.0 => x,
(a, b) => Op::Mul(Arc::new(a), Arc::new(b)),
}
}
}
impl Mul<f32> for Op {
type Output = Self;
fn mul(self, other: f32) -> Self {
match self {
Op::Const(x) => Op::Const(x * other),
x if other == 1.0 => x,
x => Op::Mul(Arc::new(x), Arc::new(Op::Const(other))),
}
}
}
impl Div<Self> for Op {
type Output = Self;
fn div(self, other: Self) -> Self {
match (self, other) {
(Op::Const(a), Op::Const(b)) => Op::Const(a / b),
(x, Op::Const(y)) if y == 1.0 => x,
(a, b) => Op::Div(Arc::new(a), Arc::new(b)),
}
}
}
impl Div<f32> for Op {
type Output = Self;
fn div(self, other: f32) -> Self {
match self {
Op::Const(x) => Op::Const(x / other),
x if other == 1.0 => x,
x => Op::Div(Arc::new(x), Arc::new(Op::Const(other))),
}
}
}
impl Neg for Op {
type Output = Self;
fn neg(self) -> Self {
match self {
Op::Neg(x) => (*x).clone(),
x => Op::Neg(Arc::new(x)),
}
}
}
pub fn circle(radius: f32) -> Sdf {
Sdf((Op::X.pow(2) + Op::Y.pow(2)).sqrt() - radius)
}
pub fn sphere(radius: f32) -> Sdf {
Sdf((Op::X.pow(2) + Op::Y.pow(2) + Op::Z.pow(2)).sqrt() - radius)
}
pub fn cylinder(radius: f32, height: f32) -> Sdf {
circle(radius).extrude(height)
}
// float sdArc( vec3 p, vec3 b )
// {
// vec3 q = abs(p) - b;
// return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);
// // }
// pub fn cube(side: f32) -> Sdf {
// }
#[derive(Debug)]
pub struct Sdf(pub Op);
impl Sdf {
pub fn extrude(&self, height: f32) -> Self {
Sdf((-Op::Z).max(Op::Z - height).max(self.0.clone()))
}
pub fn translate(&self, x: f32, y: f32, z: f32) -> Self {
Sdf(self.0.clone().remap(Op::X - x, Op::Y - y, Op::Z - z))
}
pub fn orient(&self, axis: Vector) -> Self {
todo!()
}
pub fn union(&self, other: &Self) -> Self {
Sdf(self.0.clone().min(other.0.clone()))
}
pub fn intersection(&self, other: &Self) -> Self {
Sdf(self.0.clone().max(other.0.clone()))
}
pub fn subtract(&self, other: &Self) -> Self {
Sdf((-self.0.clone()).max(other.0.clone()))
}
pub fn slow_eval(&self, p: (f32, f32, f32)) -> f32 {
slow_sdf(p, &self.0)
}
}
impl BitOr<Self> for Sdf {
type Output = Sdf;
/// union
fn bitor(self, other: Self) -> Sdf {
self.union(&other)
}
}
impl BitOr<&'_ Self> for Sdf {
type Output = Sdf;
/// union
fn bitor(self, other: &Self) -> Sdf {
self.union(other)
}
}
impl BitOr<Self> for &'_ Sdf {
type Output = Sdf;
/// union
fn bitor(self, other: Self) -> Sdf {
self.union(&other)
}
}
impl BitOr<&'_ Self> for &'_ Sdf {
type Output = Sdf;
/// union
fn bitor(self, other: &Self) -> Sdf {
self.union(other)
}
}
impl BitOrAssign for Sdf {
fn bitor_assign(&mut self, rhs: Self) {
*self = mem::replace(self, Sdf(Op::X)) | rhs;
}
}
impl BitAnd for Sdf {
type Output = Sdf;
/// intersection
fn bitand(self, rhs: Self) -> Sdf {
self.union(&rhs)
}
}
impl BitAnd for &'_ Sdf {
type Output = Sdf;
/// intersection
fn bitand(self, rhs: Self) -> Sdf {
self.union(&rhs)
}
}
impl BitAndAssign for Sdf {
fn bitand_assign(&mut self, rhs: Self) {
*self = mem::replace(self, Sdf(Op::X)) & rhs;
}
}
impl Sub for Sdf {
type Output = Sdf;
fn sub(self, other: Self) -> Sdf {
self.subtract(&other)
}
}
impl Sub for &'_ Sdf {
type Output = Sdf;
fn sub(self, other: Self) -> Sdf {
self.subtract(other)
}
}
impl SubAssign for Sdf {
fn sub_assign(&mut self, rhs: Self) {
*self = mem::replace(self, Sdf(Op::X)) - rhs;
}
}
pub struct Vector { pub x: f32, pub y: f32, pub z: f32 }
pub const X: Vector = Vector { x: 1.0, y: 0.0, z: 0.0 };
pub const Y: Vector = Vector { x: 0.0, y: 1.0, z: 0.0 };
pub const Z: Vector = Vector { x: 0.0, y: 0.0, z: 1.0 };
fn main() {
let mut s = sphere(1.0);
let c = cylinder(1.0, 0.5).translate(0.5, 0.0, 0.0);
s -= c.repeat_circular(3, s.center);
println!("{:?}", s);
println!("distance: {}", s.slow_eval((0.0, 0.0, 5.0)))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment