pub fn sphere(p: [f32; 3], radius: f32) -> f32 {
length(p) - radius
}
pub fn box_sdf(p: [f32; 3], size: [f32; 3]) -> f32 {
let q = [
p[0].abs() - size[0],
p[1].abs() - size[1],
p[2].abs() - size[2],
];
length([q[0].max(0.0), q[1].max(0.0), q[2].max(0.0)]) + q[0].max(q[1].max(q[2])).min(0.0)
}
pub fn torus(p: [f32; 3], major: f32, minor: f32) -> f32 {
let q = [(p[0] * p[0] + p[2] * p[2]).sqrt() - major, p[1]];
length2(q) - minor
}
pub fn cylinder(p: [f32; 3], radius: f32, height: f32) -> f32 {
let d = [
(p[0] * p[0] + p[2] * p[2]).sqrt() - radius,
p[1].abs() - height,
];
d[0].max(d[1]).min(0.0) + length2([d[0].max(0.0), d[1].max(0.0)])
}
pub fn plane(p: [f32; 3], normal: [f32; 3], offset: f32) -> f32 {
p[0] * normal[0] + p[1] * normal[1] + p[2] * normal[2] + offset
}
pub fn smin(a: f32, b: f32, k: f32) -> f32 {
let h = (0.5 + 0.5 * (b - a) / k).clamp(0.0, 1.0);
b * (1.0 - h) + a * h - k * h * (1.0 - h)
}
pub fn smax(a: f32, b: f32, k: f32) -> f32 {
-smin(-a, -b, k)
}
fn length(v: [f32; 3]) -> f32 {
(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt()
}
fn length2(v: [f32; 2]) -> f32 {
(v[0] * v[0] + v[1] * v[1]).sqrt()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sphere_origin() {
assert!((sphere([0.0, 0.0, 0.0], 1.0) - (-1.0)).abs() < 1e-6);
}
#[test]
fn test_sphere_surface() {
assert!(sphere([1.0, 0.0, 0.0], 1.0).abs() < 1e-6);
}
#[test]
fn test_sphere_outside() {
assert!(sphere([2.0, 0.0, 0.0], 1.0) > 0.0);
}
#[test]
fn test_box_origin() {
assert!(box_sdf([0.0, 0.0, 0.0], [1.0, 1.0, 1.0]) < 0.0);
}
#[test]
fn test_box_surface() {
assert!(box_sdf([1.0, 0.0, 0.0], [1.0, 1.0, 1.0]).abs() < 1e-6);
}
#[test]
fn test_torus() {
assert!(torus([2.5, 0.0, 0.0], 2.0, 0.5).abs() < 1e-5);
}
#[test]
fn test_plane() {
assert!((plane([0.0, 1.0, 0.0], [0.0, 1.0, 0.0], 0.0) - 1.0).abs() < 1e-6);
}
#[test]
fn test_smin() {
assert!((smin(0.1, 5.0, 0.5) - 0.1).abs() < 0.15);
assert!(smin(1.0, 2.0, 0.5) <= 1.0);
}
#[test]
fn test_cylinder() {
assert!(cylinder([0.0, 0.0, 0.0], 1.0, 1.0) < 0.0);
assert!(cylinder([1.0, 0.0, 0.0], 1.0, 1.0).abs() < 1e-5);
}
}