Add generic trait Surface

This commit is contained in:
bijan2005 2020-11-30 09:41:15 -05:00
parent 6a7a3c7774
commit ff625f576f
5 changed files with 40 additions and 32 deletions

View file

@ -52,11 +52,10 @@ fn render(camera: &Camera, scene: &Scene, filename: &str) -> std::io::Result<()>
fn main() -> std::io::Result<()> {
let camera = Camera::new(Point3::new(0.0,0.0,0.0), Vector3::new(0.0,0.0,-1.0), 1.0, 2.0, 2.0, 400, 400);
let camera = Camera::new(Point3::new(0.0,0.0,0.0), Vector3::new(0.0,0.0,-1.0), 1.0, 2.0, 2.0, 500, 500);
let scene = vec![
Object::Sphere(Sphere::new_solid(0.0,0.0,-5.0,2.0, Color::white())),
Object::Sphere(Sphere::new_solid(-3.0,0.0,-8.0,2.5, Color::white()))
Object::new(Sphere::new(0.0,0.0,-3.0,2.0, |x, y| Color::new(x, 0.0, y * 2.0)))
];
render(&camera, &scene, "out.ppm")

View file

@ -1,4 +1,5 @@
mod base; pub use base::*;
mod sphere; pub use sphere::*;
mod plane; pub use plane::*;
mod triangle; pub use triangle::*;
@ -7,28 +8,18 @@ use na::*;
use crate::types::*;
pub enum Object {
Sphere(Sphere)
pub struct Object {
pub surface: Box<dyn Surface>
}
impl Object {
pub fn intersect(&self, ray: Ray) -> Option<f32> {
match *self {
Object::Sphere(ref sphere) => sphere.intersect(ray)
}
pub fn new<S: 'static + Surface>(surface: S) -> Self {
Object { surface: Box::new(surface) }
}
pub fn getcolor(&self, point: Point3<f32>) -> Color {
match *self {
Object::Sphere(ref sphere) => sphere.getcolor(point)
}
}
pub fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> {
match *self {
Object::Sphere(ref sphere) => sphere.normal(point)
}
}
pub fn intersect(&self, ray: Ray) -> Option<f32> { self.surface.intersect(ray) }
pub fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> { self.surface.normal(point) }
pub fn getcolor(&self, point: Point3<f32>) -> Color { self.surface.getcolor(point) }
}
pub type Scene = Vec<Object>;

14
src/object/base.rs Normal file
View file

@ -0,0 +1,14 @@
extern crate nalgebra as na;
use na::*;
use na::geometry::Point3;
use crate::types::*;
pub trait Surface {
fn intersect(&self, ray: Ray) -> Option<f32>;
fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>>;
fn getcolor(&self, point: Point3<f32>) -> Color;
}

View file

@ -4,6 +4,7 @@ use na::*;
use na::geometry::Point3;
use crate::types::*;
use super::base::*;
pub struct Plane {
pub center: Point3<f32>,
@ -25,8 +26,10 @@ impl Plane {
pub fn new_solid(center: Point3<f32>, normal: Vector3<f32>, color: Color) -> Self
{ Plane::new(center, normal, move |_, _| color) }
}
pub fn intersect(&self, ray: Ray) -> Option<f32> {
impl Surface for Plane {
fn intersect(&self, ray: Ray) -> Option<f32> {
let d = self.normal.dot(&ray.direction);
if d < 1e-6 { return None; }
@ -37,9 +40,9 @@ impl Plane {
else { None }
}
pub fn getcolor(&self, point: Point3<f32>) -> Color {
fn normal(&self, _point: Point3<f32>) -> Unit<Vector3<f32>> { self.normal }
fn getcolor(&self, point: Point3<f32>) -> Color {
unimplemented!()
}
pub fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> { self.normal }
}

View file

@ -6,6 +6,7 @@ use na::*;
use na::geometry::Point3;
use crate::types::*;
use super::base::*;
pub struct Sphere {
pub center: Point3<f32>,
@ -27,10 +28,10 @@ impl Sphere {
pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, color: Color) -> Self
{ Sphere::new(x, y, z, radius, move |_, _| color) }
}
// Determines if a ray intersects the circle.
// If so, returns the distance to the intersection point.
pub fn intersect(&self, ray: Ray) -> Option<f32> {
impl Surface for Sphere {
fn intersect(&self, ray: Ray) -> Option<f32> {
fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
let discr = b * b - 4.0 * a * c;
@ -58,7 +59,11 @@ impl Sphere {
else { None }
}
pub fn getcolor(&self, point: Point3<f32>) -> Color {
fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> {
Unit::new_normalize(point - self.center)
}
fn getcolor(&self, point: Point3<f32>) -> Color {
let normal = self.normal(point);
// In this particular case, the normal is simular to a point on a unit sphere
@ -71,8 +76,4 @@ impl Sphere {
(*self.texture)(x, y)
}
pub fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>> {
Unit::new_normalize(point - self.center)
}
}