Add solid and checker texture

This commit is contained in:
max.nuding 2022-07-05 15:57:29 +02:00
parent 93cbb67b39
commit 28105145c4
Failed to extract signature
4 changed files with 99 additions and 9 deletions

View File

@ -1,14 +1,18 @@
use crate::{Point3, Ray, Vec3}; use crate::{Point3, Ray, Vec3};
use crate::material::{Material}; use crate::material::{Material};
use crate::aabb::Aabb; use crate::aabb::Aabb;
use std::f64::consts::PI;
pub type HittableList = Vec<Box<dyn Hittable + Sync>>; pub type HittableList = Vec<Box<dyn Hittable + Sync>>;
#[derive(Debug, Clone, Copy)] //#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct HitRecord<'material> { pub struct HitRecord<'material> {
pub point: Point3, pub point: Point3,
pub normal: Vec3, pub normal: Vec3,
pub t: f64, pub t: f64,
pub u: f64,
pub v: f64,
pub front_face: bool, pub front_face: bool,
pub material: &'material Material pub material: &'material Material
} }
@ -18,7 +22,7 @@ pub trait Hittable {
fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb>; fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb>;
} }
#[derive(Clone)] //#[derive(Clone)]
pub struct Sphere { pub struct Sphere {
pub center: Point3, pub center: Point3,
pub radius: f64, pub radius: f64,
@ -28,6 +32,19 @@ impl Sphere {
pub fn new(center: Point3, radius: f64, material: Material) -> Sphere { pub fn new(center: Point3, radius: f64, material: Material) -> Sphere {
Sphere { center, radius, material } Sphere { center, radius, material }
} }
pub fn uv(point: &Point3) -> (f64, f64) {
// p: a given point on the sphere of radius one, centered at the origin.
// u: returned value [0,1] of angle around the Y axis from X=-1.
// v: returned value [0,1] of angle from Y=-1 to Y=+1.
// <1 0 0> yields <0.50 0.50> <-1 0 0> yields <0.00 0.50>
// <0 1 0> yields <0.50 1.00> < 0 -1 0> yields <0.50 0.00>
// <0 0 1> yields <0.25 0.50> < 0 0 -1> yields <0.75 0.50>
let theta = -(point.y()).acos();
let phi = -(point.z()).atan2(point.x()) + PI;
(phi / (2.0 * PI), theta / PI)
}
} }
impl Default for Sphere { impl Default for Sphere {
fn default() -> Self { fn default() -> Self {
@ -57,11 +74,14 @@ impl Hittable for Sphere {
let normal = (point - self.center) / self.radius; let normal = (point - self.center) / self.radius;
let dot = ray.direction().dot(&normal); let dot = ray.direction().dot(&normal);
let front_face = dot < 0.0; let front_face = dot < 0.0;
let (u, v) = Sphere::uv(&normal);
let normal = if front_face { normal } else { -normal }; let normal = if front_face { normal } else { -normal };
Some(HitRecord { Some(HitRecord {
point, point,
normal, normal,
t: root, t: root,
u,
v,
front_face, front_face,
material: &self.material material: &self.material
}) })
@ -75,7 +95,7 @@ impl Hittable for Sphere {
} }
} }
#[derive(Clone)] //#[derive(Clone)]
pub struct MovableSphere { pub struct MovableSphere {
pub center0: Point3, pub center0: Point3,
pub center1: Point3, pub center1: Point3,
@ -130,13 +150,16 @@ impl Hittable for MovableSphere {
let normal = (point - self.center(ray.time())) / self.radius; let normal = (point - self.center(ray.time())) / self.radius;
let dot = ray.direction().dot(&normal); let dot = ray.direction().dot(&normal);
let front_face = dot < 0.0; let front_face = dot < 0.0;
let (u, v) = Sphere::uv(&normal);
let normal = if front_face { normal } else { -normal }; let normal = if front_face { normal } else { -normal };
Some(HitRecord { Some(HitRecord {
point, point,
normal, normal,
t: root, t: root,
u,
v,
front_face, front_face,
material: &self.material material: &self.material,
}) })
} }
fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb> { fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb> {

View File

@ -13,6 +13,7 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
use crate::material::{Dielectric, Lambertian, Material, Metal}; use crate::material::{Dielectric, Lambertian, Material, Metal};
use crate::aabb::Aabb; use crate::aabb::Aabb;
use crate::bvh::BVH; use crate::bvh::BVH;
use crate::texture::CheckerTexture;
mod vec3; mod vec3;
mod ray; mod ray;
@ -22,11 +23,16 @@ mod camera;
mod output; mod output;
mod aabb; mod aabb;
mod bvh; mod bvh;
mod texture;
fn random_scene() -> HittableList { fn random_scene() -> HittableList {
let mut world:HittableList = Vec::new(); let mut world:HittableList = Vec::new();
let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5))); //let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
let checker = CheckerTexture::colored(
Color::new(0.2, 0.3, 0.1),
Color::new(0.9, 0.9, 0.9));
let material_ground = Material::Lambertian(Lambertian::textured(Box::new(checker)));
let ground = Sphere { let ground = Sphere {
center: Point3::new(0.0, -1000.0, 0.0), center: Point3::new(0.0, -1000.0, 0.0),
radius: 1000.0, radius: 1000.0,

View File

@ -1,12 +1,13 @@
use rand::Rng; use rand::Rng;
use crate::hittable::HitRecord; use crate::hittable::HitRecord;
use crate::{Color, Ray, Vec3}; use crate::{Color, Ray, Vec3};
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)>;
} }
#[derive(Debug, Clone)] //#[derive(Debug, Clone)]
pub enum Material { pub enum Material {
Lambertian(Lambertian), Lambertian(Lambertian),
Metal(Metal), Metal(Metal),
@ -29,12 +30,16 @@ impl Scatterable for Material {
} }
} }
#[derive(Debug, Clone)] //#[derive(Debug, Clone)]
pub struct Lambertian { pub struct Lambertian {
pub albedo: Color pub albedo: Box<dyn Texture>
} }
impl Lambertian { impl Lambertian {
pub fn new(albedo: Color) -> Self { pub fn new(albedo: Color) -> Self {
let texture = SolidColor::from(albedo);
Lambertian { albedo: Box::new(texture) }
}
pub fn textured(albedo: Box<dyn Texture>) -> Self {
Lambertian { albedo } Lambertian { albedo }
} }
} }
@ -46,7 +51,7 @@ impl Scatterable for Lambertian {
direction = hit_record.normal; direction = hit_record.normal;
} }
let scattered = Ray::new(hit_record.point, direction, ray.time()); let scattered = Ray::new(hit_record.point, direction, ray.time());
Some((Some(scattered), self.albedo)) Some((Some(scattered), self.albedo.value(hit_record.u, hit_record.v, &hit_record.point)))
} }
} }

56
src/texture.rs Normal file
View File

@ -0,0 +1,56 @@
use crate::{Point3, Color};
pub trait Texture: Sync {
fn value(&self, u: f64, v: f64, point: &Point3) -> Color;
}
pub struct SolidColor {
color_value: Color
}
impl SolidColor {
pub fn new(red: f64, green: f64, blue: f64) -> Self {
SolidColor {
color_value: Color::new(red, green, blue)
}
}
}
impl From<Color> for SolidColor {
fn from(color: Color) -> Self {
SolidColor { color_value: color }
}
}
impl Texture for SolidColor {
fn value(&self, _u: f64, _v: f64, _point: &Point3) -> Color {
self.color_value
}
}
pub struct CheckerTexture {
pub odd: Box<dyn Texture>,
pub even: Box<dyn Texture>
}
impl CheckerTexture {
pub fn colored(color1: Color, color2: Color) -> Self {
CheckerTexture {
even: Box::new(SolidColor::from(color1)),
odd: Box::new(SolidColor::from(color2)),
}
}
}
impl Texture for CheckerTexture {
fn value(&self, u: f64, v: f64, point: &Point3) -> Color {
let sines = (10.0 * point.x().sin()) *
(10.0 * point.y().sin()) *
(10.0 * point.z().sin());
match sines {
sines if sines < 0.0 => self.odd.value(u, v, point),
_ => self.even.value(u, v, point),
}
}
}