Compare commits
0
Commits
No files matched your search
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"camera": {
|
|
||||||
"image_width": 1920,
|
|
||||||
"image_height": 1080,
|
|
||||||
"anti_alias_rate": 23,
|
|
||||||
"max_depth": 50,
|
|
||||||
"fov": 20.0,
|
|
||||||
"look_from": { "x": -10, "y": 5, "z": 10 },
|
|
||||||
"look_at": { "x": 0.0, "y": 0.0, "z": -1.0 },
|
|
||||||
"vup": { "x": 0.0, "y": 1.0, "z": 0.0 },
|
|
||||||
"defocus_blur": false,
|
|
||||||
"defocus_angle": 2,
|
|
||||||
"focus_dist": 15.68
|
|
||||||
},
|
|
||||||
"materials": [
|
|
||||||
{ "type": "metal", "albedo": { "x": 0.2, "y": 0.4, "z": 0.8 }, "prob": 1.0, "fuzz": 0.1 },
|
|
||||||
{ "type": "metal", "albedo": { "x": 0.7, "y": 0.4, "z": 0.2 }, "prob": 1.0, "fuzz": 0.1 },
|
|
||||||
{ "type": "lambertian", "albedo": { "x": 0.8, "y": 0.8, "z": 0.0 }, "prob": 1.0 },
|
|
||||||
{ "type": "lambertian", "albedo": { "x": 0.1, "y": 0.2, "z": 0.5 }, "prob": 1.0 },
|
|
||||||
{ "type": "dielectric", "refraction_index": 1.5},
|
|
||||||
{ "type": "dielectric", "refraction_index": 0.67},
|
|
||||||
{ "type": "metal", "albedo": { "x": 0.8, "y": 0.6, "z": 0.2 }, "prob": 1.0, "fuzz": 1.0 }
|
|
||||||
|
|
||||||
],
|
|
||||||
"objects": [
|
|
||||||
{ "type": "sphere", "center": { "x": 0, "y": 0.7, "z": -0.4 }, "radius": 0.2, "material": 0},
|
|
||||||
{ "type": "sphere", "center": { "x": 0.0, "y": 0.5, "z": -0.8 }, "radius": 0.1, "material": 1},
|
|
||||||
{ "type": "sphere", "center": { "x": 0.0, "y": -100.5, "z": -1.0 }, "radius": 100.0, "material": 2},
|
|
||||||
{ "type": "sphere", "center": { "x": 0.0, "y": 0.0, "z": -1.2 }, "radius": 0.5, "material": 3},
|
|
||||||
{ "type": "sphere", "center": { "x": -1, "y": 0, "z": -1 }, "radius": 0.4, "material": 5},
|
|
||||||
{ "type": "sphere", "center": { "x": 1, "y": 0, "z": -1 }, "radius": 0.5, "material": 6},
|
|
||||||
{ "type": "sphere", "center": { "x": 20, "y": 7, "z": -15 }, "radius": 10.5, "material": 0}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
"camera": {
|
"camera": {
|
||||||
"image_width": 1920,
|
"image_width": 1920,
|
||||||
"image_height": 1080,
|
"image_height": 1080,
|
||||||
"anti_alias_rate": 2,
|
"anti_alias_rate": 23,
|
||||||
"max_depth": 10,
|
"max_depth": 100,
|
||||||
"fov": 20.0,
|
"fov": 20.0,
|
||||||
"look_from": { "x": -10, "y": 5, "z": 10 },
|
"look_from": { "x": -10, "y": 5, "z": 10 },
|
||||||
"look_at": { "x": 0.0, "y": 0.0, "z": -1.0 },
|
"look_at": { "x": 0.0, "y": 0.0, "z": -1.0 },
|
||||||
|
|||||||
+4
-4
@@ -183,7 +183,7 @@ impl Camera {
|
|||||||
|
|
||||||
fn defocus_disk_sample(&self) -> Vec3 {
|
fn defocus_disk_sample(&self) -> Vec3 {
|
||||||
let p = Vec3::random_in_unit_disk();
|
let p = Vec3::random_in_unit_disk();
|
||||||
self.look_from + (p.x() * self.defocus_disk_u) + (p.y() * self.defocus_disk_v)
|
return self.look_from + (p.x() * self.defocus_disk_u) + (p.y() * self.defocus_disk_v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&mut self, hittables: &Vec<Arc<dyn Hittable>>) {
|
pub fn render(&mut self, hittables: &Vec<Arc<dyn Hittable>>) {
|
||||||
@@ -209,7 +209,7 @@ impl Camera {
|
|||||||
let ray_orig = if self.defocus_angle > 0. { self.defocus_disk_sample() } else {self.look_from};
|
let ray_orig = if self.defocus_angle > 0. { self.defocus_disk_sample() } else {self.look_from};
|
||||||
let ray_dir = pixel_loc - ray_orig;
|
let ray_dir = pixel_loc - ray_orig;
|
||||||
let r = Ray::new(ray_orig, ray_dir);
|
let r = Ray::new(ray_orig, ray_dir);
|
||||||
pixel_colour += self.ray_colour(hittables, &r, self.max_depth);
|
pixel_colour += self.ray_colour(&hittables, &r, self.max_depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,11 +220,11 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("Writing image file...");
|
info!("Writing image file...");
|
||||||
imgbuf.save("output2.png").unwrap();
|
imgbuf.save("output.png").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ray_colour(&self, hittables: &Vec<Arc<dyn Hittable>>, r: &Ray, depth: u32) -> Colour {
|
fn ray_colour(&self, hittables: &Vec<Arc<dyn Hittable>>, r: &Ray, depth: u32) -> Colour {
|
||||||
if depth == 0 {
|
if depth <= 0 {
|
||||||
return Colour::default();
|
return Colour::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+78
-86
@@ -9,16 +9,68 @@ mod vec3;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::camera::Camera;
|
|
||||||
use crate::objects::materials::dielectric::Dielectric;
|
use crate::objects::materials::dielectric::Dielectric;
|
||||||
use crate::objects::materials::lambertian::{Lambertian, Metal};
|
use crate::objects::materials::lambertian::{Lambertian, Metal};
|
||||||
|
use crate::objects::materials::traits::Material;
|
||||||
use crate::objects::sphere::Sphere;
|
use crate::objects::sphere::Sphere;
|
||||||
use crate::objects::traits::Hittable;
|
use crate::objects::traits::Hittable;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::scenes::scene::Scene;
|
use crate::scenes::scene::Scene;
|
||||||
use crate::vec3::Vec3;
|
use crate::vec3::Vec3;
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
use log::info;
|
||||||
|
use pretty_env_logger;
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
|
||||||
|
fn random_material() -> Arc<dyn Material> {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let col = Vec3::new(rng.random(), rng.random(), rng.random());
|
||||||
|
match rng.random_range(0..3) {
|
||||||
|
0 => Arc::new(Lambertian::new(col, 1.)),
|
||||||
|
1 => Arc::new(Metal::new(col, 1., rng.random())),
|
||||||
|
2 => Arc::new(Dielectric::new(rng.random_range(0.3..1.9))),
|
||||||
|
_ => Arc::new(Metal::new(col, 0., rng.random())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_sphere_on_floor<T: Hittable>(
|
||||||
|
materials: &Vec<Arc<dyn Material>>,
|
||||||
|
existing: &Vec<T>,
|
||||||
|
max_size: f32,
|
||||||
|
) -> Sphere {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let r = rng.random_range(0.1..max_size);
|
||||||
|
let mut sphere = Sphere::xyz(
|
||||||
|
rng.random_range((-50.)..50.),
|
||||||
|
rng.random_range(0.1..max_size),
|
||||||
|
rng.random_range((-50.)..50.),
|
||||||
|
r,
|
||||||
|
materials.choose(&mut rng).unwrap().clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut isct = true;
|
||||||
|
let mut attempts_left = 49;
|
||||||
|
while isct && attempts_left > 0 {
|
||||||
|
isct = false;
|
||||||
|
for h in existing {
|
||||||
|
if h.inside(&h.closest_on_surface(sphere.center())) {
|
||||||
|
info!("Generating sphere failed, {} attempts left", attempts_left);
|
||||||
|
isct = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isct {
|
||||||
|
sphere.set_center(Vec3::new(
|
||||||
|
rng.random_range(0.5..100.),
|
||||||
|
r,
|
||||||
|
rng.random_range(0.5..100.),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
attempts_left -= 1;
|
||||||
|
}
|
||||||
|
sphere
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: implement scene serialization
|
// TODO: implement scene serialization
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -27,94 +79,34 @@ fn main() {
|
|||||||
|
|
||||||
// TODO: use cli arg for scenefile
|
// TODO: use cli arg for scenefile
|
||||||
let json_file = "./scenes/scene.json";
|
let json_file = "./scenes/scene.json";
|
||||||
|
// let json_file = "./scenes/failsMatBounds.json";
|
||||||
let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!");
|
let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!");
|
||||||
let mut scene: Scene = serde_json::from_str(&json_str).unwrap();
|
let mut scene: Scene = serde_json::from_str(&json_str).unwrap();
|
||||||
scene.render();
|
scene.render();
|
||||||
return;
|
|
||||||
|
|
||||||
// random spheres code; thought: make this available as cli flag?
|
// random spheres code; thought: make this available as cli flag?
|
||||||
let ground = Lambertian::rgb(0.5, 0.5, 0.5, 1.);
|
// let mut materials: Vec<Arc<dyn Material>> = vec![Arc::new(Lambertian::rgb(0.1, 0.1, 0.2, 0.8))];
|
||||||
let mut world: Vec<Arc<dyn Hittable>> = vec![Arc::new(Sphere::xyz(
|
// for i in 0..15 {
|
||||||
0.,
|
// info!("Generating {}th material.", i + 1);
|
||||||
-1000.,
|
// materials.push(random_material());
|
||||||
0.,
|
// }
|
||||||
1000.,
|
//
|
||||||
Arc::new(ground),
|
// let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())];
|
||||||
))];
|
// for i in 0..40 {
|
||||||
|
// info!("Generating {}th sphere.", i + 1);
|
||||||
let mut rng = rand::rng();
|
// world.push(random_sphere_on_floor(
|
||||||
let point = Vec3::new(4., 0.2, 0.);
|
// &materials,
|
||||||
for a in -11..11 {
|
// &world,
|
||||||
for b in -11..11 {
|
// ((i + 1) as f32).ln() + (15. as f32).log(10.),
|
||||||
let mat = rng.random_range((0.)..1.);
|
// ));
|
||||||
let center = Vec3::new(
|
// }
|
||||||
a as f32 + 0.9 * rng.random_range((0.)..1.),
|
//
|
||||||
0.2,
|
// // let mut c = Camera::new(400, 300);
|
||||||
b as f32 + 0.9 * rng.random_range((0.)..1.),
|
// let mut c = Camera::new(1920, 1080);
|
||||||
);
|
// c.set_fov(60.);
|
||||||
|
// c.set_anti_alias_rate(1);
|
||||||
if (center - point).length() > 0.9 {
|
// c.set_max_depth(10);
|
||||||
if mat < 0.8 {
|
// c.set_look_from(Vec3::new(-60., 10., 1.));
|
||||||
// diffuse
|
// c.set_look_at(Vec3::new(0., 0., 0.));
|
||||||
world.push(Arc::new(Sphere::new(
|
// c.render(&world);
|
||||||
center,
|
|
||||||
0.2,
|
|
||||||
Arc::new(Lambertian::new(Vec3::random() * Vec3::random(), 1.)),
|
|
||||||
)));
|
|
||||||
} else if mat < 0.95 {
|
|
||||||
// metal
|
|
||||||
world.push(Arc::new(Sphere::new(
|
|
||||||
center,
|
|
||||||
0.2,
|
|
||||||
Arc::new(Metal::rgb(
|
|
||||||
rng.random_range(0.5..1.),
|
|
||||||
rng.random_range(0.5..1.),
|
|
||||||
rng.random_range(0.5..1.),
|
|
||||||
1.,
|
|
||||||
rng.random_range((0.)..0.5),
|
|
||||||
)),
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
// glass
|
|
||||||
world.push(Arc::new(Sphere::new(
|
|
||||||
center,
|
|
||||||
0.2,
|
|
||||||
Arc::new(Dielectric::new(1.5)),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
world.push(Arc::new(Sphere::xyz(
|
|
||||||
0.,
|
|
||||||
1.,
|
|
||||||
0.,
|
|
||||||
1.,
|
|
||||||
Arc::new(Dielectric::new(1.5)),
|
|
||||||
)));
|
|
||||||
world.push(Arc::new(Sphere::xyz(
|
|
||||||
-4.,
|
|
||||||
1.,
|
|
||||||
0.,
|
|
||||||
1.,
|
|
||||||
Arc::new(Lambertian::rgb(0.4, 0.2, 0.1, 1.)),
|
|
||||||
)));
|
|
||||||
world.push(Arc::new(Sphere::xyz(
|
|
||||||
4.,
|
|
||||||
1.,
|
|
||||||
0.,
|
|
||||||
1.,
|
|
||||||
Arc::new(Metal::rgb(0.7, 0.6, 0.5, 1., 0.)),
|
|
||||||
)));
|
|
||||||
|
|
||||||
let mut c = Camera::new(1920, 1080);
|
|
||||||
c.set_fov(20.);
|
|
||||||
c.set_anti_alias_rate(23);
|
|
||||||
c.set_max_depth(50);
|
|
||||||
c.set_look_from(Vec3::new(13., 2., 3.));
|
|
||||||
c.set_look_at(Vec3::new(0., 0., 0.));
|
|
||||||
c.add_defocus_blur(0.6, 10.);
|
|
||||||
|
|
||||||
c.render(&world);
|
|
||||||
}
|
}
|
||||||
+5
-5
@@ -17,11 +17,11 @@ pub struct Hit {
|
|||||||
impl Hit {
|
impl Hit {
|
||||||
pub fn new(t: f32, p: Vec3, n: Vec3, mat: Arc<dyn Material>, front_face: bool) -> Self {
|
pub fn new(t: f32, p: Vec3, n: Vec3, mat: Arc<dyn Material>, front_face: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
t,
|
t: t,
|
||||||
p,
|
p: p,
|
||||||
n: if front_face { n } else { -n },
|
n: if front_face { n } else { -n },
|
||||||
mat,
|
mat: mat,
|
||||||
front_face,
|
front_face: front_face,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +57,6 @@ impl Hit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closest
|
return closest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,15 +17,15 @@ pub struct Dielectric {
|
|||||||
impl Dielectric {
|
impl Dielectric {
|
||||||
pub fn new(refraction_index: f32) -> Self {
|
pub fn new(refraction_index: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
refraction_index,
|
refraction_index: refraction_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflectance(cos: f32, refraction_index: f32) -> f32 {
|
fn _reflectance(cos: f32, refraction_index: f32) -> f32 {
|
||||||
// Shlick's approximation
|
// Shlick's approximation
|
||||||
let mut r0 = (1. - refraction_index) / (1. + refraction_index);
|
let mut r0 = (1. - refraction_index) / (1. + refraction_index);
|
||||||
r0 *= r0;
|
r0 *= r0;
|
||||||
r0 + (1. - r0) * (1. - cos).powf(5.)
|
return r0 + (1. - r0) * (1. - cos).powf(5.);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,12 +45,13 @@ impl Material for Dielectric {
|
|||||||
let sin_theta = sqrt(1. - cos_theta * cos_theta);
|
let sin_theta = sqrt(1. - cos_theta * cos_theta);
|
||||||
let cannot_refract = ri * sin_theta > 1.;
|
let cannot_refract = ri * sin_theta > 1.;
|
||||||
|
|
||||||
|
let dir: Vec3;
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
let dir = if cannot_refract || Dielectric::reflectance(cos_theta, ri) > rng.random::<f32>() {
|
if cannot_refract || Dielectric::_reflectance(cos_theta, ri) > rng.random::<f32>() {
|
||||||
unit.reflect(hit.n())
|
dir = unit.reflect(hit.n());
|
||||||
} else {
|
} else {
|
||||||
unit.refract(hit.n(), ri)
|
dir = unit.refract(hit.n(), ri);
|
||||||
};
|
}
|
||||||
Some((Ray::new(*hit.p(), dir), Colour::new(1., 1., 1.)))
|
Some((Ray::new(*hit.p(), dir), Colour::new(1., 1., 1.)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,21 +16,21 @@ pub struct Lambertian {
|
|||||||
impl Lambertian {
|
impl Lambertian {
|
||||||
pub fn new(albedo: Colour, prob: f32) -> Self {
|
pub fn new(albedo: Colour, prob: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
albedo,
|
albedo: albedo,
|
||||||
prob,
|
prob: prob,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rgb(r: f32, g: f32, b: f32, prob: f32) -> Self {
|
pub fn rgb(r: f32, g: f32, b: f32, prob: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
albedo: Colour::new(r, g, b),
|
albedo: Colour::new(r, g, b),
|
||||||
prob,
|
prob: prob,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material for Lambertian {
|
impl Material for Lambertian {
|
||||||
fn scatter(&self, hit: &Hit, _ray: &Ray) -> Option<(Ray, Colour)> {
|
fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)> {
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
if self.prob >= rng.random::<f32>() {
|
if self.prob >= rng.random::<f32>() {
|
||||||
let mut dir = *hit.n() + Vec3::random_unit();
|
let mut dir = *hit.n() + Vec3::random_unit();
|
||||||
@@ -40,7 +40,7 @@ impl Material for Lambertian {
|
|||||||
let scattered = Ray::new(*hit.p(), dir);
|
let scattered = Ray::new(*hit.p(), dir);
|
||||||
return Some((scattered, self.albedo));
|
return Some((scattered, self.albedo));
|
||||||
}
|
}
|
||||||
None
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,17 +54,17 @@ pub struct Metal {
|
|||||||
impl Metal {
|
impl Metal {
|
||||||
pub fn new(albedo: Colour, prob: f32, fuzz: f32) -> Self {
|
pub fn new(albedo: Colour, prob: f32, fuzz: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
albedo,
|
albedo: albedo,
|
||||||
prob,
|
prob: prob,
|
||||||
fuzz,
|
fuzz: fuzz,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rgb(r: f32, g: f32, b: f32, prob: f32, fuzz: f32) -> Self {
|
pub fn rgb(r: f32, g: f32, b: f32, prob: f32, fuzz: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
albedo: Colour::new(r, g, b),
|
albedo: Colour::new(r, g, b),
|
||||||
prob,
|
prob: prob,
|
||||||
fuzz,
|
fuzz: fuzz,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,6 +77,6 @@ impl Material for Metal {
|
|||||||
refl = refl.get_unit() + self.fuzz * Vec3::random_unit();
|
refl = refl.get_unit() + self.fuzz * Vec3::random_unit();
|
||||||
return Some((Ray::new(*hit.p(), refl), self.albedo));
|
return Some((Ray::new(*hit.p(), refl), self.albedo));
|
||||||
}
|
}
|
||||||
None
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{objects::hit::Hit, ray::Ray, vec3::Colour};
|
use crate::{objects::hit::Hit, ray::Ray, vec3::Colour};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait Material: Debug + Send + Sync{
|
pub trait Material: Debug {
|
||||||
fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)>;
|
fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)>;
|
||||||
}
|
}
|
||||||
+20
-2
@@ -2,6 +2,7 @@ use core::f32::math::sqrt;
|
|||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::objects::hit::Hit;
|
use crate::objects::hit::Hit;
|
||||||
use crate::objects::materials::traits::Material;
|
use crate::objects::materials::traits::Material;
|
||||||
@@ -15,7 +16,6 @@ pub struct Sphere {
|
|||||||
material: Arc<dyn Material>,
|
material: Arc<dyn Material>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Debug for Sphere {
|
impl Debug for Sphere {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Sphere")
|
f.debug_struct("Sphere")
|
||||||
@@ -29,7 +29,7 @@ impl Debug for Sphere {
|
|||||||
impl Sphere {
|
impl Sphere {
|
||||||
pub fn new(center: Vec3, r: f32, mat: Arc<dyn Material>) -> Self {
|
pub fn new(center: Vec3, r: f32, mat: Arc<dyn Material>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
center,
|
center: center,
|
||||||
radius: r,
|
radius: r,
|
||||||
material: mat,
|
material: mat,
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,16 @@ impl Sphere {
|
|||||||
material: mat,
|
material: mat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn center(&self) -> &Vec3 {
|
||||||
|
&self.center
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_center(&mut self, center: Vec3) {
|
||||||
|
if self.center != center {
|
||||||
|
self.center = center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hittable for Sphere {
|
impl Hittable for Sphere {
|
||||||
@@ -73,4 +83,12 @@ impl Hittable for Sphere {
|
|||||||
fn normal_at(&self, p: &Vec3) -> Vec3 {
|
fn normal_at(&self, p: &Vec3) -> Vec3 {
|
||||||
(*p - self.center).get_unit()
|
(*p - self.center).get_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inside(&self, p: &Vec3) -> bool {
|
||||||
|
(*p - self.center).length() < self.radius
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closest_on_surface(&self, p: &Vec3) -> Vec3 {
|
||||||
|
self.normal_at(p) * self.radius
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,10 @@ use crate::objects::hit::Hit;
|
|||||||
use crate::Ray;
|
use crate::Ray;
|
||||||
use crate::Vec3;
|
use crate::Vec3;
|
||||||
|
|
||||||
pub trait Hittable: Debug + Send + Sync {
|
pub trait Hittable: Debug {
|
||||||
fn hit(&self, r: &Ray) -> Option<Hit>;
|
fn hit(&self, r: &Ray) -> Option<Hit>;
|
||||||
fn normal_at(&self, p: &Vec3) -> Vec3;
|
fn normal_at(&self, p: &Vec3) -> Vec3;
|
||||||
|
// fn intersect<H: Hittable>(&self, o: &H) -> bool;
|
||||||
|
fn inside(&self, p: &Vec3) -> bool;
|
||||||
|
fn closest_on_surface(&self, p: &Vec3) -> Vec3;
|
||||||
}
|
}
|
||||||
+2
-2
@@ -8,8 +8,8 @@ pub struct Ray {
|
|||||||
impl Ray {
|
impl Ray {
|
||||||
pub fn new(origin: Vec3, dir: Vec3) -> Self {
|
pub fn new(origin: Vec3, dir: Vec3) -> Self {
|
||||||
Self {
|
Self {
|
||||||
origin,
|
origin: origin,
|
||||||
dir,
|
dir: dir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -83,7 +83,7 @@ impl Vec3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn length_squared(&self) -> f32 {
|
pub fn length_squared(&self) -> f32 {
|
||||||
self.x * self.x + self.y * self.y + self.z * self.z
|
(self.x * self.x + self.y * self.y + self.z * self.z) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dot(&self, other: &Self) -> f32 {
|
pub fn dot(&self, other: &Self) -> f32 {
|
||||||
@@ -123,7 +123,7 @@ impl Vec3 {
|
|||||||
let r_out_perp = etai_over_etat * (*self + cos_theta * n);
|
let r_out_perp = etai_over_etat * (*self + cos_theta * n);
|
||||||
let r_out_parr = -sqrt((1. - r_out_perp.length_squared()).abs()) * n;
|
let r_out_parr = -sqrt((1. - r_out_perp.length_squared()).abs()) * n;
|
||||||
|
|
||||||
r_out_perp + r_out_parr
|
return r_out_perp + r_out_parr;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn output(self) -> image::Rgb<u8> {
|
pub fn output(self) -> image::Rgb<u8> {
|
||||||
|
|||||||