Add light
This commit is contained in:
parent
19107f20c9
commit
11c4d2c991
84
src/main.rs
84
src/main.rs
@ -1,6 +1,5 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::camera::Camera;
|
use crate::camera::Camera;
|
||||||
use crate::hittable::{Sphere, HittableList, HittableObject};
|
use crate::hittable::{Sphere, HittableList, HittableObject};
|
||||||
use crate::output::{Output, PNG};
|
use crate::output::{Output, PNG};
|
||||||
@ -10,7 +9,7 @@ use hittable::MovableSphere;
|
|||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::distributions::{Distribution, Uniform};
|
use rand::distributions::{Distribution, Uniform};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use crate::material::{Dielectric, Lambertian, Material, Metal};
|
use crate::material::{Dielectric, DiffuseLight, Lambertian, Material, Metal};
|
||||||
use crate::aabb::Aabb;
|
use crate::aabb::Aabb;
|
||||||
use crate::image_texture::ImageTexture;
|
use crate::image_texture::ImageTexture;
|
||||||
use crate::noise::NoiseTexture;
|
use crate::noise::NoiseTexture;
|
||||||
@ -37,7 +36,45 @@ const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize;
|
|||||||
const SAMPLES_PER_PIXEL: i32 = 100;
|
const SAMPLES_PER_PIXEL: i32 = 100;
|
||||||
const MAX_DEPTH: i32 = 50;
|
const MAX_DEPTH: i32 = 50;
|
||||||
|
|
||||||
fn earth() -> (HittableList, Camera) {
|
struct Scene {
|
||||||
|
pub world: HittableList,
|
||||||
|
pub cam: Camera,
|
||||||
|
pub background: Color
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sun() -> Scene {
|
||||||
|
let mut world:HittableList = Vec::new();
|
||||||
|
let earth_material = Arc::new(
|
||||||
|
Material::DiffuseLight(DiffuseLight::from(Color::new(1.0, 1.0, 0.0))));
|
||||||
|
world.push(Arc::new(Sphere {
|
||||||
|
center: Point3::new(0.0, 0.0, 0.0),
|
||||||
|
radius: 2.0,
|
||||||
|
material: earth_material
|
||||||
|
}));
|
||||||
|
|
||||||
|
let look_from = Point3::new(13.0, 2.0, 3.0);
|
||||||
|
let look_at = Point3::new(0.0, 0.0, 0.0);
|
||||||
|
let focus_dist = 2.0;
|
||||||
|
|
||||||
|
let cam = Camera::new(
|
||||||
|
look_from,
|
||||||
|
look_at,
|
||||||
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
ASPECT_RATIO,
|
||||||
|
20.0,
|
||||||
|
0.0,
|
||||||
|
focus_dist,
|
||||||
|
0.0,
|
||||||
|
1.0);
|
||||||
|
|
||||||
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn earth() -> Scene {
|
||||||
let mut world:HittableList = Vec::new();
|
let mut world:HittableList = Vec::new();
|
||||||
let earth_texture = ImageTexture::new("textures/earthmap.jpg");
|
let earth_texture = ImageTexture::new("textures/earthmap.jpg");
|
||||||
let earth_material = Arc::new(
|
let earth_material = Arc::new(
|
||||||
@ -63,10 +100,14 @@ fn earth() -> (HittableList, Camera) {
|
|||||||
0.0,
|
0.0,
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
(world, cam)
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::new(0.70, 0.80, 1.00)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn two_spheres() -> (HittableList, Camera) {
|
fn two_spheres() -> Scene {
|
||||||
let mut world:HittableList = Vec::new();
|
let mut world:HittableList = Vec::new();
|
||||||
let checker = CheckerTexture::colored(
|
let checker = CheckerTexture::colored(
|
||||||
Color::new(0.2, 0.3, 0.1),
|
Color::new(0.2, 0.3, 0.1),
|
||||||
@ -98,9 +139,13 @@ fn two_spheres() -> (HittableList, Camera) {
|
|||||||
0.0,
|
0.0,
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
(world, cam)
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::new(0.70, 0.80, 1.00)
|
||||||
}
|
}
|
||||||
fn two_perlin_spheres() -> (HittableList, Camera) {
|
}
|
||||||
|
fn two_perlin_spheres() -> Scene {
|
||||||
let mut world:HittableList = Vec::new();
|
let mut world:HittableList = Vec::new();
|
||||||
let noise = NoiseTexture { noise: Perlin::new(), scale: 4.0 };
|
let noise = NoiseTexture { noise: Perlin::new(), scale: 4.0 };
|
||||||
let noise_material = Arc::new(Material::Lambertian(Lambertian::textured(Arc::new(noise))));
|
let noise_material = Arc::new(Material::Lambertian(Lambertian::textured(Arc::new(noise))));
|
||||||
@ -130,10 +175,14 @@ fn two_perlin_spheres() -> (HittableList, Camera) {
|
|||||||
0.0,
|
0.0,
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
(world, cam)
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::new(0.70, 0.80, 1.00)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_scene() -> (HittableList, Camera) {
|
fn random_scene() -> Scene {
|
||||||
let mut world: HittableList = Vec::new();
|
let mut world: HittableList = Vec::new();
|
||||||
|
|
||||||
let checker = CheckerTexture::colored(
|
let checker = CheckerTexture::colored(
|
||||||
@ -225,17 +274,22 @@ fn random_scene() -> (HittableList, Camera) {
|
|||||||
0.0,
|
0.0,
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
(world, cam)
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::new(0.70, 0.80, 1.00)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// World
|
// World
|
||||||
let scene: u8 = 2;
|
let scene: u8 = 3;
|
||||||
let (world, cam) = match scene {
|
let scene_setup = match scene {
|
||||||
0 => two_spheres(),
|
0 => two_spheres(),
|
||||||
1 => two_perlin_spheres(),
|
1 => two_perlin_spheres(),
|
||||||
2 => earth(),
|
2 => earth(),
|
||||||
_ => random_scene()
|
3 => sun(),
|
||||||
|
_ => random_scene(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let between = Uniform::from(0.0..1.0);
|
let between = Uniform::from(0.0..1.0);
|
||||||
@ -253,8 +307,8 @@ fn main() {
|
|||||||
let random_number = between.sample(&mut rng);
|
let random_number = between.sample(&mut rng);
|
||||||
let u = (col as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
|
let u = (col as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
|
||||||
let v = (row as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
|
let v = (row as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
|
||||||
let ray = cam.get_ray(u, v);
|
let ray = scene_setup.cam.get_ray(u, v);
|
||||||
color += ray.pixel_color(&world, MAX_DEPTH);
|
color += ray.pixel_color(scene_setup.background, &scene_setup.world, MAX_DEPTH);
|
||||||
});
|
});
|
||||||
let bytes = color.into_bytes(SAMPLES_PER_PIXEL);
|
let bytes = color.into_bytes(SAMPLES_PER_PIXEL);
|
||||||
pixel[0] = bytes[0];
|
pixel[0] = bytes[0];
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use crate::hittable::HitRecord;
|
use crate::hittable::HitRecord;
|
||||||
use crate::{Color, Ray, Vec3};
|
use crate::{Color, Point3, Ray, Vec3};
|
||||||
use crate::texture::{SolidColor, Texture};
|
use crate::texture::{SolidColor, Texture};
|
||||||
|
|
||||||
pub trait Scatterable {
|
pub trait Scatterable {
|
||||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)>;
|
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)>;
|
||||||
|
fn emitted(&self, u: f64, v: f64, point: &Point3) -> Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Material {
|
pub enum Material {
|
||||||
Lambertian(Lambertian),
|
Lambertian(Lambertian),
|
||||||
Metal(Metal),
|
Metal(Metal),
|
||||||
Dielectric(Dielectric)
|
Dielectric(Dielectric),
|
||||||
|
DiffuseLight(DiffuseLight)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Material {
|
impl Default for Material {
|
||||||
@ -25,9 +27,37 @@ impl Scatterable for Material {
|
|||||||
match self {
|
match self {
|
||||||
Material::Lambertian(l) => l.scatter(ray, hit_record),
|
Material::Lambertian(l) => l.scatter(ray, hit_record),
|
||||||
Material::Metal(m) => m.scatter(ray, hit_record),
|
Material::Metal(m) => m.scatter(ray, hit_record),
|
||||||
Material::Dielectric(d) => d.scatter(ray, hit_record)
|
Material::Dielectric(d) => d.scatter(ray, hit_record),
|
||||||
|
Material::DiffuseLight(l) => l.scatter(ray, hit_record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn emitted(&self, u: f64, v: f64, point: &Point3) -> Color {
|
||||||
|
match self {
|
||||||
|
Material::DiffuseLight(l) => l.emitted(u, v, point),
|
||||||
|
_ => Color::new(0.0, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiffuseLight {
|
||||||
|
pub emit: Arc<dyn Texture>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for DiffuseLight {
|
||||||
|
fn from(color: Color) -> Self {
|
||||||
|
DiffuseLight {
|
||||||
|
emit: Arc::new(SolidColor::from(color))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiffuseLight {
|
||||||
|
pub fn emitted(&self, u: f64, v: f64, point: &Point3) -> Color {
|
||||||
|
self.emit.value(u, v, point)
|
||||||
|
}
|
||||||
|
pub fn scatter(&self, _ray: &Ray, _hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Lambertian {
|
pub struct Lambertian {
|
||||||
@ -43,8 +73,8 @@ impl Lambertian {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scatterable for Lambertian {
|
impl Lambertian {
|
||||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||||
let mut direction = hit_record.normal + Vec3::random_unit_vector();
|
let mut direction = hit_record.normal + Vec3::random_unit_vector();
|
||||||
if direction.near_zero() {
|
if direction.near_zero() {
|
||||||
direction = hit_record.normal;
|
direction = hit_record.normal;
|
||||||
@ -69,8 +99,8 @@ impl Metal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scatterable for Metal {
|
impl Metal {
|
||||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||||
let reflected = ray.direction().unit_vector().reflected(&hit_record.normal);
|
let reflected = ray.direction().unit_vector().reflected(&hit_record.normal);
|
||||||
let scattered = Ray::new(
|
let scattered = Ray::new(
|
||||||
hit_record.point,
|
hit_record.point,
|
||||||
@ -99,8 +129,8 @@ impl Dielectric {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scatterable for Dielectric {
|
impl Dielectric {
|
||||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||||
let color = Color::new(1.0, 1.0, 1.0);
|
let color = Color::new(1.0, 1.0, 1.0);
|
||||||
let refraction_ratio = if hit_record.front_face {
|
let refraction_ratio = if hit_record.front_face {
|
||||||
1.0/self.index_of_refraction
|
1.0/self.index_of_refraction
|
||||||
|
34
src/ray.rs
34
src/ray.rs
@ -25,30 +25,58 @@ impl Ray {
|
|||||||
pub fn direction(&self) -> Vec3 { self.direction }
|
pub fn direction(&self) -> Vec3 { self.direction }
|
||||||
pub fn origin(&self) -> Point3 { self.origin }
|
pub fn origin(&self) -> Point3 { self.origin }
|
||||||
pub fn time(&self) -> f64 { self.time }
|
pub fn time(&self) -> f64 { self.time }
|
||||||
pub fn pixel_color(&self, world: &HittableList, depth: i32) -> Color {
|
pub fn pixel_color(&self, background: Color, world: &HittableList, depth: i32) -> Color {
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
return Color::default();
|
return Color::default();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if let Some(rect) = self.hit_world(world, 0.001, f64::INFINITY) {
|
if let Some(rect) = self.hit_world(world, 0.001, f64::INFINITY) {
|
||||||
let scattered = rect.material.scatter(self, &rect);
|
let scattered = rect.material.scatter(self, &rect);
|
||||||
return match scattered {
|
return match scattered {
|
||||||
Some((scattered_ray, albedo)) => {
|
Some((scattered_ray, albedo)) => {
|
||||||
match scattered_ray {
|
match scattered_ray {
|
||||||
Some(sr) => {
|
Some(sr) => {
|
||||||
albedo * sr.pixel_color(world, depth-1)
|
albedo * sr.pixel_color(background, world, depth-1)
|
||||||
},
|
},
|
||||||
None => albedo
|
None => albedo
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => { return Color::default() }
|
None => { return background }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let unit_direction = self.direction().unit_vector();
|
||||||
|
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||||
|
return (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0);
|
||||||
|
//return background;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Hot nothing, display sky color
|
//Hot nothing, display sky color
|
||||||
let unit_direction = self.direction().unit_vector();
|
let unit_direction = self.direction().unit_vector();
|
||||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||||
(1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0)
|
(1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0)
|
||||||
|
//return background;
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
match self.hit_world(world, 0.001, f64::INFINITY) {
|
||||||
|
Some(rect) => {
|
||||||
|
let scattered = rect.material.scatter(self, &rect);
|
||||||
|
let emitted = rect.material.emitted(rect.u, rect.v, &rect.point);
|
||||||
|
match scattered {
|
||||||
|
Some((scattered, albedo)) => {
|
||||||
|
match scattered {
|
||||||
|
Some(scattered) => {
|
||||||
|
emitted + albedo * scattered.pixel_color(background, world, depth-1)
|
||||||
|
},
|
||||||
|
None => albedo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => emitted
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => background
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn hit_world<'material>(
|
fn hit_world<'material>(
|
||||||
&self,
|
&self,
|
||||||
|
Loading…
Reference in New Issue
Block a user