initial commit

This commit is contained in:
2021-04-14 19:14:35 +02:00
commit a715710dd2
28 changed files with 2258 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
use crate::structs::Vec3;
use crate::object::Obj;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cuboid {
center: Vec3,
radius: Vec3
}
impl Cuboid {
pub fn new(center: Vec3, radius: Vec3) -> Cuboid {
Cuboid { center, radius }
}
pub fn new_xyz(cx: f64, cy: f64, cz: f64, rx: f64, ry: f64, rz: f64) -> Cuboid {
let center = Vec3::new(cx, cy, cz);
let radius = Vec3::new(rx, ry, rz);
Cuboid { center, radius }
}
}
impl Obj for Cuboid {
fn distance_to(&self, point: Vec3) -> f64 {
let dx = point.x() - self.center.x();
let dy = point.y() - self.center.y();
let dz = point.z() - self.center.z();
if dx.abs()<self.radius.x() && dy.abs()<self.radius.y() && dz.abs()<self.radius.z() {
-f64::min(
f64::min(
f64::min(
f64::abs(dx-self.radius.x()),
f64::abs(dx+self.radius.x())
),
f64::abs(dy-self.radius.y())
),
f64::min(
f64::min(
f64::abs(dy+self.radius.y()),
f64::abs(dz-self.radius.z())
),
f64::abs(dz+self.radius.z())
)
)
} else {
let dx0 = f64::max(0., dx.abs()-self.radius.x());
let dy0 = f64::max(0., dy.abs()-self.radius.y());
let dz0 = f64::max(0., dz.abs()-self.radius.z());
f64::sqrt(dx0*dx0 + dy0*dy0 + dz0*dz0)
}
}
fn normal_at(&self, point: Vec3) -> Vec3 {
let dx = (point.x()-self.center.y())/self.radius.x();
let dy = (point.y()-self.center.y())/self.radius.y();
let dz = (point.z()-self.center.z())/self.radius.z();
let (adx, ady, adz) = (dx.abs(), dy.abs(), dz.abs());
Vec3::new(
if adx>=ady && adx>adz { if dx>0. { 1. } else { -1. }} else { 0. },
if ady>=adz && ady>adx { if dy>0. { 1. } else { -1. }} else { 0. },
if adz>=adx && adz>ady { if dz>0. { 1. } else { -1. }} else { 0. },
)
}
}
+23
View File
@@ -0,0 +1,23 @@
use crate::structs::Vec3;
use crate::object::Obj;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cylinder {
center: Vec3,
radius: f64
}
impl Cylinder {
pub const fn new(center: Vec3, radius: f64) -> Cylinder {
Cylinder { center, radius }
}
}
impl Obj for Cylinder {
fn distance_to(&self, point: Vec3) -> f64 {
Vec3::new(self.center.x(), 0., self.center.z()).distance_to(point) - self.radius
}
fn normal_at(&self, point: Vec3) -> Vec3 {
point - Vec3::new(self.center.x(), 0.,self.center.z())
}
}
+45
View File
@@ -0,0 +1,45 @@
use crate::object::Obj;
use crate::light::Light;
use crate::structs::Vec3;
use std::vec;
use crate::material::Material;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Intersection<A: Obj, B: Obj> {
a: A,
b: B
}
impl<A: Obj, B: Obj> Intersection<A, B> {
pub fn new(a: A, b: B) -> Intersection<A, B> {
Intersection { a, b }
}
}
impl<A: Obj, B: Obj> Obj for Intersection<A, B> {
fn distance_to(&self, point: Vec3) -> f64 {
f64::max(self.a.distance_to(point), self.b.distance_to(point))
}
fn normal_at(&self, point: Vec3) -> Vec3 {
if self.a.distance_to(point) > self.b.distance_to(point) {
self.a.normal_at(point)
} else {
self.b.normal_at(point)
}
}
fn material_at(&self, point: Vec3) -> Material {
if self.a.distance_to(point) > self.b.distance_to(point) {
self.a.material_at(point)
} else {
self.b.material_at(point)
}
}
fn get_lights(&self) -> vec::Vec<Light> {
let mut l = self.a.get_lights();
l.extend(self.b.get_lights());
l
}
fn node_count(&self) -> u32 {
self.a.node_count() + self.b.node_count() + 1
}
}
+71
View File
@@ -0,0 +1,71 @@
use crate::consts::{EPSILON, MAX_DIST};
use crate::structs::{Vec3, O, X, Y, Z};
use crate::material::Material;
use crate::material;
use crate::light::Light;
use std::vec::Vec;
mod sphere;
mod plane;
mod union;
mod intersection;
mod cuboid;
mod cylinder;
mod torus;
mod waves;
mod with_material;
mod with_lights;
mod transform;
mod scene;
pub trait Obj: Send + Sync {
fn distance_to(&self, _point: Vec3) -> f64 {
MAX_DIST
}
fn normal_at(&self, point: Vec3) -> Vec3 {
let v = self.distance_to(point);
let x = self.distance_to(point + X*EPSILON) - v;
let y = self.distance_to(point + Y*EPSILON) - v;
let z = self.distance_to(point + Z*EPSILON) - v;
Vec3::new(x, y, z).unit()
}
fn material_at(&self, _point: Vec3) -> Material {
material::WHITE
}
fn get_lights(&self) -> Vec<Light> {
Vec::new()
}
fn node_count(&self) -> u32 { 1 }
}
impl<T: Obj> Obj for &T {
fn distance_to(&self, point: Vec3) -> f64 { (*self).distance_to(point) }
fn normal_at(&self, point: Vec3) -> Vec3 { (*self).normal_at(point) }
fn material_at(&self, point: Vec3) -> Material { (*self).material_at(point) }
fn get_lights(&self) -> Vec<Light> { (*self).get_lights() }
fn node_count(&self) -> u32 { (*self).node_count() }
}
pub trait ObjClone: Obj {
fn clone_obj(&self) -> Box<dyn ObjClone>;
}
impl<T: 'static + Obj + Clone> ObjClone for T {
fn clone_obj(&self) -> Box<dyn ObjClone> {
Box::new(self.clone())
}
}
pub use sphere::Sphere;
pub use plane::Plane;
pub use union::Union;
pub use intersection::Intersection;
pub use cuboid::Cuboid;
pub use cylinder::Cylinder;
pub use torus::Torus;
pub use waves::Waves;
pub use with_material::{WithMaterial, WithDynamicMaterial};
pub use with_lights::{WithLights, WithLight};
pub use transform::AffineTransform;
pub use scene::Scene;
+31
View File
@@ -0,0 +1,31 @@
use crate::structs::Vec3;
use crate::object::Obj;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Plane {
normal: Vec3,
offset: f64
}
impl Plane {
pub fn new(normal: Vec3, offset: f64) -> Plane {
let l = normal.magnitude();
Plane { normal: normal/l, offset: offset/l }
}
pub fn new_xyz(x: f64, y: f64, z: f64, offset: f64) -> Plane {
let normal = Vec3::new(x, y, z);
Plane::new(normal, offset)
}
pub const unsafe fn new_raw(normal: Vec3, offset: f64) -> Plane {
Plane { normal, offset }
}
}
impl Obj for Plane {
fn distance_to(&self, point: Vec3) -> f64 {
point*self.normal + self.offset
}
fn normal_at(&self, _point: Vec3) -> Vec3 {
self.normal
}
}
+31
View File
@@ -0,0 +1,31 @@
use crate::object::{Obj, ObjClone};
use crate::structs::Vec3;
use crate::material::Material;
use crate::light::Light;
pub struct Scene {
scene: Box<dyn ObjClone>
}
impl Scene {
pub fn new<T: 'static + ObjClone>(scene: T) -> Scene {
Scene { scene: Box::new(scene) }
}
pub fn new_from_box(scene: Box<dyn ObjClone>) -> Scene {
Scene { scene }
}
}
impl Obj for Scene {
fn distance_to(&self, point: Vec3) -> f64 { self.scene.distance_to(point) }
fn normal_at(&self, point: Vec3) -> Vec3 { self.scene.normal_at(point) }
fn material_at(&self, point: Vec3) -> Material { self.scene.material_at(point) }
fn get_lights(&self) -> Vec<Light> { self.scene.get_lights() }
fn node_count(&self) -> u32 { self.scene.node_count() + 1 }
}
impl Clone for Scene {
fn clone(&self) -> Scene {
Scene { scene: self.scene.clone_obj() }
}
}
+27
View File
@@ -0,0 +1,27 @@
use crate::structs::Vec3;
use crate::object::Obj;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Sphere {
pos: Vec3,
radius: f64
}
impl Sphere {
pub const fn new(pos: Vec3, radius: f64) -> Sphere {
Sphere { pos, radius }
}
pub const fn new_xyz(x: f64, y: f64, z: f64, radius: f64) -> Sphere {
let pos = Vec3::new(x, y, z);
Sphere { pos, radius }
}
}
impl Obj for Sphere {
fn distance_to(&self, point: Vec3) -> f64 {
self.pos.distance_to(point) - self.radius
}
fn normal_at(&self, point: Vec3) -> Vec3 {
(point - self.pos).unit()
}
}
+34
View File
@@ -0,0 +1,34 @@
use crate::structs::Vec3;
use crate::object::Obj;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Torus {
center: Vec3,
radius: f64,
thickness: f64
}
impl Torus {
pub const fn new(center: Vec3, radius: f64, thickness: f64) -> Torus {
Torus { center, radius, thickness }
}
pub const fn new_xyz(x: f64, y: f64, z: f64, radius: f64, thickness: f64) -> Torus {
Torus::new(Vec3::new(x, y, z), radius, thickness)
}
}
impl Obj for Torus {
fn distance_to(&self, point: Vec3) -> f64 {
let (dx, dy) = (point.x()-self.center.x(), point.y()-self.center.y());
let dh = f64::abs(f64::sqrt(dx*dx + dy*dy) - self.radius);
let dz = point.z() - self.center.z();
f64::sqrt(dh*dh + dz*dz) - self.thickness
}
fn normal_at(&self, point: Vec3) -> Vec3 {
let centered = point - self.center;
let centered_no_z= Vec3::new(centered.x(), centered.y(), 0.);
let closest = centered_no_z.unit() * self.radius;
(centered - closest).unit()
}
}
+83
View File
@@ -0,0 +1,83 @@
use crate::object::Obj;
use crate::structs::{Mat3, Vec3, O, I3};
use crate::material::Material;
use crate::light::Light;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct AffineTransform<T: Obj + Clone> {
obj: T,
transform: Mat3,
transform_inv: Mat3,
translate: Vec3
}
impl<T: Obj + Clone> AffineTransform<T> {
pub fn new(obj: T, transform: Mat3, translate: Vec3) -> AffineTransform<T> {
AffineTransform { obj, transform, transform_inv: transform.invert(), translate }
}
pub fn new_linear(obj: T, transform: Mat3) -> AffineTransform<T> {
AffineTransform { obj, transform, transform_inv: transform.invert(), translate: O }
}
pub fn new_translate(obj: T, translate: Vec3) -> AffineTransform<T> {
AffineTransform { obj, transform: I3, transform_inv: I3, translate }
}
fn apply_rev(&self, point: Vec3) -> Vec3 {
self.transform_inv*point - self.translate
}
fn apply_fwd(&self, point: Vec3) -> Vec3 {
self.transform*point + self.translate
}
}
pub const SWAP_XY: Mat3 = Mat3::new(
0., 1., 0.,
1., 0., 0.,
0., 0., 1.,
);
pub const SWAP_XZ: Mat3 = Mat3::new(
0., 0., 1.,
0., 1., 0.,
1., 0., 0.,
);
pub const SWAP_YZ: Mat3 = Mat3::new(
1., 0., 0.,
0., 0., 1.,
0., 1., 0.,
);
pub const fn scale_xyz(x: f64, y: f64, z: f64) -> Mat3 {
Mat3::new(
x , 0., 0.,
0., y , 0.,
0., 0., z ,
)
}
pub const fn scale(k: f64) -> Mat3 { scale_xyz(k, k, k) }
pub const fn scale_x(k: f64) -> Mat3 { scale_xyz(k, 1., 1.) }
pub const fn scale_y(k: f64) -> Mat3 { scale_xyz(1., k, 1.) }
pub const fn scale_z(k: f64) -> Mat3 { scale_xyz(1., 1., k) }
impl<T: Obj + Clone> Obj for AffineTransform<T> {
fn distance_to(&self, point: Vec3) -> f64 {
self.obj.distance_to(self.apply_rev(point))
}
fn normal_at(&self, point: Vec3) -> Vec3 {
self.apply_fwd(self.obj.normal_at(self.apply_rev(point)))
}
fn material_at(&self, point: Vec3) -> Material {
self.obj.material_at(self.apply_rev(point))
}
fn get_lights(&self) -> Vec<Light> {
self.obj
.get_lights()
.into_iter()
.map(|light| {
Light::new(self.apply_fwd(light.pos()), light.color())
})
.collect()
}
fn node_count(&self) -> u32 {
self.obj.node_count() + 1
}
}
+45
View File
@@ -0,0 +1,45 @@
use crate::object::Obj;
use crate::light::Light;
use crate::structs::Vec3;
use std::vec;
use crate::material::Material;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Union<A: Obj, B: Obj> {
a: A,
b: B
}
impl<A: Obj, B: Obj> Union<A, B> {
pub fn new(a: A, b: B) -> Union<A, B> {
Union { a, b }
}
}
impl<A: Obj, B: Obj> Obj for Union<A, B> {
fn distance_to(&self, point: Vec3) -> f64 {
f64::min(self.a.distance_to(point), self.b.distance_to(point))
}
fn normal_at(&self, point: Vec3) -> Vec3 {
if self.a.distance_to(point) < self.b.distance_to(point) {
self.a.normal_at(point)
} else {
self.b.normal_at(point)
}
}
fn material_at(&self, point: Vec3) -> Material {
if self.a.distance_to(point) < self.b.distance_to(point) {
self.a.material_at(point)
} else {
self.b.material_at(point)
}
}
fn get_lights(&self) -> vec::Vec<Light> {
let mut l = self.a.get_lights();
l.extend(self.b.get_lights());
l
}
fn node_count(&self) -> u32 {
self.a.node_count() + self.b.node_count() + 1
}
}
+22
View File
@@ -0,0 +1,22 @@
use crate::object::Obj;
use crate::structs::Vec3;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Waves {}
impl Waves {
pub const fn new() -> Waves {
Waves {}
}
}
impl Obj for Waves {
fn distance_to(&self, point: Vec3) -> f64 {
let dist = point.x().sin() + point.y().sin() + point.z();
dist / f64::sqrt(3.)
}
fn normal_at(&self, point: Vec3) -> Vec3 {
Vec3::new(-point.x().cos(), -point.y().cos(), 1.).unit()
}
}
+44
View File
@@ -0,0 +1,44 @@
use crate::light::Light;
use crate::object::Obj;
use crate::structs::Vec3;
use crate::material::Material;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct WithLights<T: Obj, const N: usize> {
obj: T,
lights: [Light; N]
}
impl<T: Obj, const N: usize> WithLights<T, N> {
pub fn new(obj: T, lights: [Light; N]) -> WithLights<T, N> {
WithLights { obj, lights }
}
}
impl<T: Obj, const N: usize> Obj for WithLights<T, N> {
fn distance_to(&self, point: Vec3) -> f64 {
self.obj.distance_to(point)
}
fn normal_at(&self, point: Vec3) -> Vec3 {
self.obj.normal_at(point)
}
fn material_at(&self, point: Vec3) -> Material {
self.obj.material_at(point)
}
fn get_lights(&self) -> Vec<Light> {
let mut l = self.obj.get_lights();
l.extend(&self.lights);
l
}
fn node_count(&self) -> u32 {
self.obj.node_count() + 1
}
}
pub type WithLight<T> = WithLights<T, 1>;
impl<T: Obj> WithLight<T> {
pub fn new_one(obj: T, light: Light) -> WithLight<T> {
WithLight { obj, lights: [light; 1] }
}
}
+64
View File
@@ -0,0 +1,64 @@
use crate::object::Obj;
use crate::material::Material;
use crate::structs::Vec3;
use crate::light::Light;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct WithMaterial<T: Obj> {
obj: T,
material: Material
}
impl<T: Obj> WithMaterial<T> {
pub fn new(obj: T, material: Material) -> WithMaterial<T> {
WithMaterial { obj, material }
}
}
impl<T: Obj> Obj for WithMaterial<T> {
fn distance_to(&self, point: Vec3) -> f64 {
self.obj.distance_to(point)
}
fn normal_at(&self, point: Vec3) -> Vec3 {
self.obj.normal_at(point)
}
fn material_at(&self, point: Vec3) -> Material {
self.material
}
fn get_lights(&self) -> Vec<Light> {
self.obj.get_lights()
}
fn node_count(&self) -> u32 {
self.obj.node_count() + 1
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WithDynamicMaterial<T: Obj, F: Clone + Send + Sync + Fn(Vec3) -> Material> {
obj: T,
fun: F
}
impl<T: Obj, F: Clone + Send + Sync + Fn(Vec3) -> Material> WithDynamicMaterial<T, F> {
pub fn new(obj: T, fun: F) -> WithDynamicMaterial<T, F> {
WithDynamicMaterial { obj, fun }
}
}
impl<T: Obj, F: Clone + Send + Sync + Fn(Vec3) -> Material> Obj for WithDynamicMaterial<T, F> {
fn distance_to(&self, point: Vec3) -> f64 {
self.obj.distance_to(point)
}
fn normal_at(&self, point: Vec3) -> Vec3 {
self.obj.normal_at(point)
}
fn material_at(&self, point: Vec3) -> Material {
(self.fun)(point)
}
fn get_lights(&self) -> Vec<Light> {
self.obj.get_lights()
}
fn node_count(&self) -> u32 {
self.obj.node_count() + 1
}
}