use glam::Vec3;
use serde::{Deserialize, Serialize};
use super::SdfNode;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SdfTree {
pub version: String,
pub root: SdfNode,
pub metadata: Option<SdfMetadata>,
}
impl SdfTree {
pub fn new(root: SdfNode) -> Self {
Self {
version: env!("CARGO_PKG_VERSION").to_string(),
root,
metadata: None,
}
}
pub fn with_metadata(root: SdfNode, metadata: SdfMetadata) -> Self {
Self {
version: env!("CARGO_PKG_VERSION").to_string(),
root,
metadata: Some(metadata),
}
}
pub fn node_count(&self) -> u32 {
self.root.node_count()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SdfMetadata {
pub name: Option<String>,
pub description: Option<String>,
pub author: Option<String>,
pub bounds: Option<(Vec3, Vec3)>,
pub custom: Option<std::collections::HashMap<String, String>>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Aabb {
pub min: Vec3,
pub max: Vec3,
}
impl Aabb {
#[inline]
pub const fn new(min: Vec3, max: Vec3) -> Self {
Self { min, max }
}
#[inline]
pub const fn empty() -> Self {
Self {
min: Vec3::splat(f32::INFINITY),
max: Vec3::splat(f32::NEG_INFINITY),
}
}
#[inline]
pub fn expand_point(&mut self, point: Vec3) {
self.min = self.min.min(point);
self.max = self.max.max(point);
}
#[inline]
pub fn expand_aabb(&mut self, other: &Self) {
self.min = self.min.min(other.min);
self.max = self.max.max(other.max);
}
#[inline]
pub fn surface_area(&self) -> f32 {
let d = self.max - self.min;
2.0 * (d.x * d.y + d.y * d.z + d.z * d.x)
}
#[inline]
pub fn longest_axis(&self) -> usize {
let d = self.max - self.min;
if d.x > d.y && d.x > d.z {
0
} else if d.y > d.z {
1
} else {
2
}
}
#[inline]
pub fn signed_distance(&self, point: Vec3) -> f32 {
let q = (point - self.center()).abs() - (self.max - self.min) * 0.5;
q.max(Vec3::ZERO).length() + q.x.max(q.y.max(q.z)).min(0.0)
}
pub fn from_center_extents(center: Vec3, half_extents: Vec3) -> Self {
Self {
min: center - half_extents,
max: center + half_extents,
}
}
#[inline]
pub fn center(&self) -> Vec3 {
(self.min + self.max) * 0.5
}
pub fn size(&self) -> Vec3 {
self.max - self.min
}
pub fn half_extents(&self) -> Vec3 {
self.size() * 0.5
}
pub fn contains(&self, point: Vec3) -> bool {
point.x >= self.min.x
&& point.x <= self.max.x
&& point.y >= self.min.y
&& point.y <= self.max.y
&& point.z >= self.min.z
&& point.z <= self.max.z
}
pub fn union(&self, other: &Self) -> Self {
Self {
min: self.min.min(other.min),
max: self.max.max(other.max),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ray {
pub origin: Vec3,
pub direction: Vec3,
}
impl Ray {
pub fn new(origin: Vec3, direction: Vec3) -> Self {
Self {
origin,
direction: direction.normalize(),
}
}
pub fn at(&self, t: f32) -> Vec3 {
self.origin + self.direction * t
}
}
#[derive(Debug, Clone, Copy)]
pub struct Hit {
pub distance: f32,
pub point: Vec3,
pub normal: Vec3,
pub steps: u32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sdf_tree() {
let tree = SdfTree::new(SdfNode::sphere(1.0));
assert_eq!(tree.node_count(), 1);
}
#[test]
fn test_aabb() {
let aabb = Aabb::new(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0));
assert!(aabb.contains(Vec3::ZERO));
assert!(!aabb.contains(Vec3::new(2.0, 0.0, 0.0)));
}
}