Add light

master
max.nuding 2022-07-07 14:43:26 +02:00
parent 19107f20c9
commit 11c4d2c991
Failed to extract signature
3 changed files with 139 additions and 27 deletions

View File

@ -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];

View File

@ -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

View File

@ -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,