ft: 5,6.1: sphere class + normals
This commit is contained in:
BIN
output.png
BIN
output.png
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 33 KiB |
32
src/main.rs
32
src/main.rs
@@ -1,16 +1,40 @@
|
||||
#![feature(core_float_math)]
|
||||
|
||||
mod objects;
|
||||
mod ray;
|
||||
mod vec3;
|
||||
|
||||
use core::f32;
|
||||
use std::cmp::max;
|
||||
|
||||
use crate::objects::hit::Hit;
|
||||
use crate::objects::sphere::Sphere;
|
||||
use crate::objects::traits::{Hittable, Normal};
|
||||
use crate::ray::Ray;
|
||||
use crate::vec3::{Colour, Vec3};
|
||||
use log::info;
|
||||
use pretty_env_logger;
|
||||
|
||||
fn ray_colour(r: &Ray) -> Colour {
|
||||
fn ray_colour<T>(hittables: &Vec<T>, r: &Ray) -> Colour
|
||||
where
|
||||
T: Hittable + Normal,
|
||||
{
|
||||
let mut closest: Option<Hit> = None;
|
||||
for hittable in hittables {
|
||||
if let Some(hit) = hittable.hit(r) {
|
||||
// hit happens in front of camera and is closer than closest
|
||||
if *hit.t() > 0. && (closest.is_none() || closest.as_ref().unwrap().t() > hit.t()) {
|
||||
closest = Some(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hit) = closest {
|
||||
let n = hit.n();
|
||||
return 0.5 * Colour::new(n.x() + 1., n.y() + 1., n.z() + 1.);
|
||||
}
|
||||
|
||||
// background
|
||||
let unit_dir = r.dir().get_unit();
|
||||
let a = 0.5 * (unit_dir.y() + 1.);
|
||||
|
||||
@@ -19,8 +43,8 @@ fn ray_colour(r: &Ray) -> Colour {
|
||||
|
||||
fn main() {
|
||||
// use structs so rust-analyzer can provide lsp
|
||||
let v = Vec3::new(255., 0., 255.);
|
||||
let _ = Ray::new(v.clone(), v.clone());
|
||||
let s = Sphere::new(Vec3::new(0., 0., -1.), 0.5);
|
||||
let objects = vec![s];
|
||||
|
||||
pretty_env_logger::init();
|
||||
|
||||
@@ -56,7 +80,7 @@ fn main() {
|
||||
let r = Ray::new(camera_center, ray_dir);
|
||||
|
||||
let pixel = imgbuf.get_pixel_mut(i, j);
|
||||
*pixel = ray_colour(&r).output();
|
||||
*pixel = ray_colour(&objects, &r).output();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
src/objects.rs
Normal file
3
src/objects.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod hit;
|
||||
pub mod sphere;
|
||||
pub mod traits;
|
||||
25
src/objects/hit.rs
Normal file
25
src/objects/hit.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use crate::vec3::Vec3;
|
||||
|
||||
pub struct Hit {
|
||||
t: f32,
|
||||
p: Vec3,
|
||||
n: Vec3,
|
||||
}
|
||||
|
||||
impl Hit {
|
||||
pub fn new(t: f32, p: Vec3, n: Vec3) -> Hit {
|
||||
Hit { t: t, p: p, n: n }
|
||||
}
|
||||
|
||||
pub fn t(&self) -> &f32 {
|
||||
&self.t
|
||||
}
|
||||
|
||||
pub fn p(&self) -> &Vec3 {
|
||||
&self.p
|
||||
}
|
||||
|
||||
pub fn n(&self) -> &Vec3 {
|
||||
&self.n
|
||||
}
|
||||
}
|
||||
44
src/objects/sphere.rs
Normal file
44
src/objects/sphere.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use core::f32::math::sqrt;
|
||||
|
||||
use crate::objects::hit::Hit;
|
||||
use crate::objects::traits::{Hittable, Normal};
|
||||
use crate::Vec3;
|
||||
|
||||
pub struct Sphere {
|
||||
center: Vec3,
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(center: Vec3, radius: f32) -> Sphere {
|
||||
Sphere {
|
||||
center: center,
|
||||
radius: radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hittable for Sphere {
|
||||
fn hit(&self, r: &crate::ray::Ray) -> Option<Hit> {
|
||||
let oc = self.center - r.origin();
|
||||
let a = r.dir().dot(r.dir());
|
||||
let b = -2. * r.dir().dot(&oc);
|
||||
let c = oc.dot(&oc) - self.radius * self.radius;
|
||||
|
||||
let d = b * b - 4. * a * c;
|
||||
|
||||
if d < 0. {
|
||||
None
|
||||
} else {
|
||||
let t = (-b - sqrt(d)) / (2.0 * a);
|
||||
let p = r.at(t);
|
||||
Some(Hit::new(t, p, self.normal_at(&p)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Normal for Sphere {
|
||||
fn normal_at(&self, p: &Vec3) -> Vec3 {
|
||||
(*p - self.center).get_unit()
|
||||
}
|
||||
}
|
||||
11
src/objects/traits.rs
Normal file
11
src/objects/traits.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use crate::objects::hit::Hit;
|
||||
use crate::Ray;
|
||||
use crate::Vec3;
|
||||
|
||||
pub trait Hittable {
|
||||
fn hit(&self, r: &Ray) -> Option<Hit>;
|
||||
}
|
||||
|
||||
pub trait Normal {
|
||||
fn normal_at(&self, p: &Vec3) -> Vec3;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ pub struct Ray {
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn at(self, t: f32) -> Vec3 {
|
||||
pub fn at(&self, t: f32) -> Vec3 {
|
||||
self.origin + t * self.dir
|
||||
}
|
||||
|
||||
|
||||
21
src/vec3.rs
21
src/vec3.rs
@@ -46,15 +46,11 @@ impl Vec3 {
|
||||
(self.r * self.r + self.g * self.g + self.b * self.b) as f32
|
||||
}
|
||||
|
||||
pub fn dot(self, other: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
r: self.r * other.r,
|
||||
g: self.g * other.g,
|
||||
b: self.b * other.b,
|
||||
}
|
||||
pub fn dot(&self, other: &Vec3) -> f32 {
|
||||
self.r * other.r + self.g * other.g + self.b * other.b
|
||||
}
|
||||
|
||||
pub fn cross(self, other: Vec3) -> Vec3 {
|
||||
pub fn cross(&self, other: &Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
r: self.g * other.b - self.b * other.g,
|
||||
g: self.b * other.r - self.r * other.b,
|
||||
@@ -142,6 +138,17 @@ impl AddAssign<f32> for Vec3 {
|
||||
};
|
||||
}
|
||||
}
|
||||
impl Sub<&Vec3> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: &Self) -> Self {
|
||||
Self {
|
||||
r: self.r - rhs.r,
|
||||
g: self.g - rhs.g,
|
||||
b: self.b - rhs.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Vec3> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
Reference in New Issue
Block a user