Add solid and checker texture
This commit is contained in:
parent
93cbb67b39
commit
28105145c4
@ -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> {
|
||||||
|
@ -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,
|
||||||
|
@ -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
56
src/texture.rs
Normal 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user