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::time::Instant;
|
||||
|
||||
use crate::camera::Camera;
|
||||
use crate::hittable::{Sphere, HittableList, HittableObject};
|
||||
use crate::output::{Output, PNG};
|
||||
@ -10,7 +9,7 @@ use hittable::MovableSphere;
|
||||
use rand::Rng;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
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::image_texture::ImageTexture;
|
||||
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 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 earth_texture = ImageTexture::new("textures/earthmap.jpg");
|
||||
let earth_material = Arc::new(
|
||||
@ -63,10 +100,14 @@ fn earth() -> (HittableList, Camera) {
|
||||
0.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 checker = CheckerTexture::colored(
|
||||
Color::new(0.2, 0.3, 0.1),
|
||||
@ -98,9 +139,13 @@ fn two_spheres() -> (HittableList, Camera) {
|
||||
0.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 noise = NoiseTexture { noise: Perlin::new(), scale: 4.0 };
|
||||
let noise_material = Arc::new(Material::Lambertian(Lambertian::textured(Arc::new(noise))));
|
||||
@ -130,10 +175,14 @@ fn two_perlin_spheres() -> (HittableList, Camera) {
|
||||
0.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 checker = CheckerTexture::colored(
|
||||
@ -225,17 +274,22 @@ fn random_scene() -> (HittableList, Camera) {
|
||||
0.0,
|
||||
1.0);
|
||||
|
||||
(world, cam)
|
||||
Scene {
|
||||
world,
|
||||
cam,
|
||||
background: Color::new(0.70, 0.80, 1.00)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// World
|
||||
let scene: u8 = 2;
|
||||
let (world, cam) = match scene {
|
||||
let scene: u8 = 3;
|
||||
let scene_setup = match scene {
|
||||
0 => two_spheres(),
|
||||
1 => two_perlin_spheres(),
|
||||
2 => earth(),
|
||||
_ => random_scene()
|
||||
3 => sun(),
|
||||
_ => random_scene(),
|
||||
};
|
||||
|
||||
let between = Uniform::from(0.0..1.0);
|
||||
@ -253,8 +307,8 @@ fn main() {
|
||||
let random_number = between.sample(&mut rng);
|
||||
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 ray = cam.get_ray(u, v);
|
||||
color += ray.pixel_color(&world, MAX_DEPTH);
|
||||
let ray = scene_setup.cam.get_ray(u, v);
|
||||
color += ray.pixel_color(scene_setup.background, &scene_setup.world, MAX_DEPTH);
|
||||
});
|
||||
let bytes = color.into_bytes(SAMPLES_PER_PIXEL);
|
||||
pixel[0] = bytes[0];
|
||||
|
@ -1,17 +1,19 @@
|
||||
use std::sync::Arc;
|
||||
use rand::Rng;
|
||||
use crate::hittable::HitRecord;
|
||||
use crate::{Color, Ray, Vec3};
|
||||
use crate::{Color, Point3, Ray, Vec3};
|
||||
use crate::texture::{SolidColor, Texture};
|
||||
|
||||
pub trait Scatterable {
|
||||
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 {
|
||||
Lambertian(Lambertian),
|
||||
Metal(Metal),
|
||||
Dielectric(Dielectric)
|
||||
Dielectric(Dielectric),
|
||||
DiffuseLight(DiffuseLight)
|
||||
}
|
||||
|
||||
impl Default for Material {
|
||||
@ -25,9 +27,37 @@ impl Scatterable for Material {
|
||||
match self {
|
||||
Material::Lambertian(l) => l.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 {
|
||||
@ -43,8 +73,8 @@ impl Lambertian {
|
||||
}
|
||||
}
|
||||
|
||||
impl Scatterable for Lambertian {
|
||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||
impl Lambertian {
|
||||
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||
let mut direction = hit_record.normal + Vec3::random_unit_vector();
|
||||
if direction.near_zero() {
|
||||
direction = hit_record.normal;
|
||||
@ -69,8 +99,8 @@ impl Metal {
|
||||
}
|
||||
}
|
||||
|
||||
impl Scatterable for Metal {
|
||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||
impl Metal {
|
||||
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||
let reflected = ray.direction().unit_vector().reflected(&hit_record.normal);
|
||||
let scattered = Ray::new(
|
||||
hit_record.point,
|
||||
@ -99,8 +129,8 @@ impl Dielectric {
|
||||
}
|
||||
}
|
||||
|
||||
impl Scatterable for Dielectric {
|
||||
fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||
impl Dielectric {
|
||||
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||
let color = Color::new(1.0, 1.0, 1.0);
|
||||
let refraction_ratio = if hit_record.front_face {
|
||||
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 origin(&self) -> Point3 { self.origin }
|
||||
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 {
|
||||
return Color::default();
|
||||
}
|
||||
/*
|
||||
if let Some(rect) = self.hit_world(world, 0.001, f64::INFINITY) {
|
||||
let scattered = rect.material.scatter(self, &rect);
|
||||
return match scattered {
|
||||
Some((scattered_ray, albedo)) => {
|
||||
match scattered_ray {
|
||||
Some(sr) => {
|
||||
albedo * sr.pixel_color(world, depth-1)
|
||||
albedo * sr.pixel_color(background, world, depth-1)
|
||||
},
|
||||
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
|
||||
let unit_direction = self.direction().unit_vector();
|
||||
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)
|
||||
//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>(
|
||||
&self,
|
||||
|
Loading…
Reference in New Issue
Block a user