De-boxed many uses of Hit and Material.

Use of generic parameter directly where possible in structures instead
of Box'd values.
Added Material implementations for Box<Material> and Arc<Material> to
aid in the automatic conversion when necessary to use a Sized value for
Material.
Implement From trait for [f32;3] to Vec3 to make some APIs Into<Vec3>
which is a bit nicer to use.
This commit is contained in:
Bill Thiede 2018-10-03 20:53:37 -07:00
parent 7684bb2088
commit 36b2fba5b7
18 changed files with 303 additions and 205 deletions

View File

@ -246,14 +246,12 @@ mod tests {
Box::new(Sphere::new(
Vec3::new(0., 0., 0.),
0.5,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.1, 0.2, 0.5,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))),
)),
Box::new(Sphere::new(
Vec3::new(1., 0., 0.),
0.5,
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2),
)),
],
0.,
@ -274,19 +272,17 @@ mod tests {
Box::new(Sphere::new(
Vec3::new(0., 0., 0.),
0.5,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.1, 0.2, 0.5,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))),
)),
Box::new(Sphere::new(
Vec3::new(1., 0., 0.),
0.5,
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2),
)),
Box::new(Sphere::new(
Vec3::new(0., 1., 0.),
0.5,
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2),
)),
],
0.,

View File

@ -19,9 +19,7 @@ pub struct Cuboid {
}
impl Cuboid {
pub fn new(p_min: Vec3, p_max: Vec3, material: Box<Material>) -> Cuboid {
let material = Arc::new(material);
pub fn new(p_min: Vec3, p_max: Vec3, material: Arc<Material>) -> Cuboid {
Cuboid {
p_min,
p_max,
@ -32,48 +30,48 @@ impl Cuboid {
p_min.y,
p_max.y,
p_max.z,
Box::new(Arc::clone(&material)),
Arc::clone(&material),
)),
Box::new(FlipNormals::new(Box::new(XYRect::new(
Box::new(FlipNormals::new(XYRect::new(
p_min.x,
p_max.x,
p_min.y,
p_max.y,
p_min.z,
Box::new(Arc::clone(&material)),
)))),
Arc::clone(&material),
))),
Box::new(XZRect::new(
p_min.x,
p_max.x,
p_min.z,
p_max.z,
p_max.y,
Box::new(Arc::clone(&material)),
Arc::clone(&material),
)),
Box::new(FlipNormals::new(Box::new(XZRect::new(
Box::new(FlipNormals::new(XZRect::new(
p_min.x,
p_max.x,
p_min.z,
p_max.z,
p_min.y,
Box::new(Arc::clone(&material)),
)))),
Arc::clone(&material),
))),
Box::new(YZRect::new(
p_min.y,
p_max.y,
p_min.z,
p_max.z,
p_max.x,
Box::new(Arc::clone(&material)),
Arc::clone(&material),
)),
Box::new(FlipNormals::new(Box::new(YZRect::new(
Box::new(FlipNormals::new(YZRect::new(
p_min.y,
p_max.y,
p_min.z,
p_max.z,
p_min.x,
Box::new(Arc::clone(&material)),
)))),
Arc::clone(&material),
))),
]),
}
}

View File

@ -3,17 +3,26 @@ use hitable::Hit;
use hitable::HitRecord;
use ray::Ray;
pub struct FlipNormals {
hitable: Box<Hit>,
pub struct FlipNormals<H>
where
H: Hit,
{
hitable: H,
}
impl FlipNormals {
pub fn new(hitable: Box<Hit>) -> FlipNormals {
impl<H> FlipNormals<H>
where
H: Hit,
{
pub fn new(hitable: H) -> FlipNormals<H> {
FlipNormals { hitable }
}
}
impl Hit for FlipNormals {
impl<H> Hit for FlipNormals<H>
where
H: Hit,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
if let Some(rec) = self.hitable.hit(r, t_min, t_max) {
return Some(HitRecord {

View File

@ -38,7 +38,7 @@ pub trait Material: Send + Sync {
}
}
impl Material for Arc<Box<Material>> {
impl Material for Arc<Material> {
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse {
(**self).scatter(r_in, rec)
}
@ -47,18 +47,36 @@ impl Material for Arc<Box<Material>> {
}
}
pub struct Lambertian {
// TODO(wathiede): implement texture sharing via references
albedo: Box<Texture>,
impl Material for Box<Material> {
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse {
(**self).scatter(r_in, rec)
}
fn emitted(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
(**self).emitted(u, v, p)
}
}
impl Lambertian {
pub fn new(texture: Box<Texture>) -> Lambertian {
pub struct Lambertian<T>
where
T: Texture,
{
// TODO(wathiede): implement texture sharing via references
albedo: T,
}
impl<T> Lambertian<T>
where
T: Texture,
{
pub fn new(texture: T) -> Lambertian<T> {
Lambertian { albedo: texture }
}
}
impl Material for Lambertian {
impl<T> Material for Lambertian<T>
where
T: Texture,
{
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse {
let target = rec.p + rec.normal + random_in_unit_sphere();
let (u, v) = rec.uv;
@ -164,17 +182,26 @@ impl Material for Dielectric {
}
}
pub struct DiffuseLight {
emit: Box<Texture>,
pub struct DiffuseLight<T>
where
T: Texture,
{
emit: T,
}
impl DiffuseLight {
pub fn new(emit: Box<Texture>) -> DiffuseLight {
impl<T> DiffuseLight<T>
where
T: Texture,
{
pub fn new(emit: T) -> DiffuseLight<T> {
DiffuseLight { emit }
}
}
impl Material for DiffuseLight {
impl<T> Material for DiffuseLight<T>
where
T: Texture,
{
fn scatter(&self, _r_in: &Ray, _rec: &HitRecord) -> ScatterResponse {
ScatterResponse {
scattered: Default::default(),

View File

@ -8,24 +8,30 @@ use sphere::get_sphere_uv;
use vec3::dot;
use vec3::Vec3;
pub struct MovingSphere {
pub struct MovingSphere<M>
where
M: Material,
{
center0: Vec3,
center1: Vec3,
radius: f32,
material: Box<Material>,
material: M,
time0: f32,
time1: f32,
}
impl MovingSphere {
impl<M> MovingSphere<M>
where
M: Material,
{
pub fn new(
center0: Vec3,
center1: Vec3,
radius: f32,
time0: f32,
time1: f32,
material: Box<Material>,
) -> MovingSphere {
material: M,
) -> MovingSphere<M> {
MovingSphere {
center0,
center1,
@ -41,7 +47,10 @@ impl MovingSphere {
}
}
impl Hit for MovingSphere {
impl<M> Hit for MovingSphere<M>
where
M: Material,
{
fn hit(&self, r: Ray, t0: f32, t1: f32) -> Option<HitRecord> {
let oc = r.origin - self.center(r.time);
let a = dot(r.direction, r.direction);
@ -58,7 +67,7 @@ impl Hit for MovingSphere {
uv,
p: point,
normal: (point - self.center(r.time)) / self.radius,
material: &*self.material,
material: &self.material,
});
}
let temp = (-b + (b * b - a * c).sqrt()) / a;
@ -70,7 +79,7 @@ impl Hit for MovingSphere {
uv,
p: point,
normal: (point - self.center(r.time)) / self.radius,
material: &*self.material,
material: &self.material,
});
}
}

View File

@ -5,17 +5,23 @@ use material::Material;
use ray::Ray;
use vec3::Vec3;
pub struct XYRect {
pub struct XYRect<M>
where
M: Material,
{
x0: f32,
x1: f32,
y0: f32,
y1: f32,
k: f32,
material: Box<Material>,
material: M,
}
impl XYRect {
pub fn new(x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: Box<Material>) -> XYRect {
impl<M> XYRect<M>
where
M: Material,
{
pub fn new(x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: M) -> XYRect<M> {
XYRect {
x0,
x1,
@ -27,7 +33,10 @@ impl XYRect {
}
}
impl Hit for XYRect {
impl<M> Hit for XYRect<M>
where
M: Material,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let t = (self.k - r.origin.z) / r.direction.z;
if t < t_min || t > t_max {
@ -45,7 +54,7 @@ impl Hit for XYRect {
uv: (u, v),
p: r.point_at_parameter(t),
normal: Vec3::new(0., 0., 1.),
material: &*self.material,
material: &self.material,
})
}
@ -57,17 +66,23 @@ impl Hit for XYRect {
}
}
pub struct XZRect {
pub struct XZRect<M>
where
M: Material,
{
x0: f32,
x1: f32,
z0: f32,
z1: f32,
k: f32,
material: Box<Material>,
material: M,
}
impl XZRect {
pub fn new(x0: f32, x1: f32, z0: f32, z1: f32, k: f32, material: Box<Material>) -> XZRect {
impl<M> XZRect<M>
where
M: Material,
{
pub fn new(x0: f32, x1: f32, z0: f32, z1: f32, k: f32, material: M) -> XZRect<M> {
XZRect {
x0,
x1,
@ -79,7 +94,10 @@ impl XZRect {
}
}
impl Hit for XZRect {
impl<M> Hit for XZRect<M>
where
M: Material,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let t = (self.k - r.origin.y) / r.direction.y;
if t < t_min || t > t_max {
@ -97,7 +115,7 @@ impl Hit for XZRect {
uv: (u, v),
p: r.point_at_parameter(t),
normal: Vec3::new(0., 1., 0.),
material: &*self.material,
material: &self.material,
})
}
@ -109,17 +127,23 @@ impl Hit for XZRect {
}
}
pub struct YZRect {
pub struct YZRect<M>
where
M: Material,
{
y0: f32,
y1: f32,
k: f32,
z0: f32,
z1: f32,
material: Box<Material>,
material: M,
}
impl YZRect {
pub fn new(y0: f32, y1: f32, z0: f32, z1: f32, k: f32, material: Box<Material>) -> YZRect {
impl<M> YZRect<M>
where
M: Material,
{
pub fn new(y0: f32, y1: f32, z0: f32, z1: f32, k: f32, material: M) -> YZRect<M> {
YZRect {
y0,
y1,
@ -131,7 +155,10 @@ impl YZRect {
}
}
impl Hit for YZRect {
impl<M> Hit for YZRect<M>
where
M: Material,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let t = (self.k - r.origin.x) / r.direction.x;
if t < t_min || t > t_max {
@ -149,7 +176,7 @@ impl Hit for YZRect {
uv: (u, v),
p: r.point_at_parameter(t),
normal: Vec3::new(1., 0., 0.),
material: &*self.material,
material: &self.material,
})
}

View File

@ -79,7 +79,7 @@ pub struct Opt {
#[structopt(short = "s", long = "subsample", default_value = "8")]
pub subsamples: usize,
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box"
#[structopt(long = "model", default_value = "cornell_box")]
#[structopt(long = "model", default_value = "book")]
pub model: Model,
/// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof
#[structopt(long = "pprof", parse(from_os_str))]

View File

@ -8,15 +8,21 @@ use hitable::HitRecord;
use ray::Ray;
use vec3::Vec3;
pub struct RotateY {
hitable: Box<Hit>,
pub struct RotateY<H>
where
H: Hit,
{
hitable: H,
sin_theta: f32,
cos_theta: f32,
bbox: Option<AABB>,
}
impl RotateY {
pub fn new(hitable: Box<Hit>, angle: f32) -> RotateY {
impl<H> RotateY<H>
where
H: Hit,
{
pub fn new(hitable: H, angle: f32) -> RotateY<H> {
let radians = PI / 180. * angle;
let sin_theta = radians.sin();
let cos_theta = radians.cos();
@ -55,7 +61,10 @@ impl RotateY {
}
}
impl Hit for RotateY {
impl<H> Hit for RotateY<H>
where
H: Hit,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let origin = Vec3::new(
self.cos_theta * r.origin[0] - self.sin_theta * r.origin[2],

View File

@ -46,9 +46,7 @@ pub fn new(opt: &Opt) -> Scene {
grid.push(Box::new(Sphere::new(
Vec3::new(x_pos, 0., z_pos),
0.5,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
r, g, b,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(r, g, b))),
)));
}
}

View File

@ -7,13 +7,13 @@ use hitable_list::HitableList;
use kdtree::KDTree;
use material::Dielectric;
use material::Lambertian;
use material::Material;
use material::Metal;
use renderer::Opt;
use renderer::Scene;
use sphere::Sphere;
use texture::CheckerTexture;
use texture::ConstantTexture;
use texture::Texture;
use vec3::Vec3;
pub fn new(opt: &Opt) -> Scene {
@ -35,9 +35,9 @@ pub fn new(opt: &Opt) -> Scene {
time_max,
);
let ground_color = if opt.use_accel {
Vec3::new(1.0, 0.4, 0.4)
[1.0, 0.4, 0.4]
} else {
Vec3::new(0.4, 1.0, 0.4)
[0.4, 1.0, 0.4]
};
let world: Box<Hit> = if opt.use_accel {
Box::new(KDTree::new(random_scene(ground_color), time_min, time_max))
@ -54,22 +54,25 @@ pub fn new(opt: &Opt) -> Scene {
}
}
fn random_scene(ground_color: Vec3) -> Vec<Box<Hit>> {
fn random_scene<V>(ground_color: V) -> Vec<Box<Hit>>
where
V: Into<Vec3>,
{
let mut rng = rand::thread_rng();
let checker = true;
let ground_texture: Box<Texture> = if checker {
Box::new(CheckerTexture::new(
Box::new(ConstantTexture::new(Vec3::new(0., 0., 0.))),
Box::new(ConstantTexture::new(ground_color)),
))
let ground_material: Box<Material> = if checker {
Box::new(Lambertian::new(CheckerTexture::new(
ConstantTexture::new([0., 0., 0.]),
ConstantTexture::new(ground_color),
)))
} else {
Box::new(ConstantTexture::new(ground_color))
Box::new(Lambertian::new(ConstantTexture::new(ground_color)))
};
let mut objects: Vec<Box<Hit>> = vec![Box::new(Sphere::new(
Vec3::new(0., -1000., 0.),
[0., -1000., 0.],
1000.,
Box::new(Lambertian::new(ground_texture)),
ground_material,
))];
let mut random = || rng.gen_range::<f32>(0., 1.);
@ -78,34 +81,34 @@ fn random_scene(ground_color: Vec3) -> Vec<Box<Hit>> {
let choose_mat = random();
let center = Vec3::new(a as f32 + 0.9 * random(), 0.2, b as f32 + 0.9 * random());
if (center - Vec3::new(4., 0.2, 0.)).length() > 0.9 {
let sphere = if choose_mat < 0.8 {
let sphere: Box<Hit> = if choose_mat < 0.8 {
// diffuse
Box::new(Sphere::new(
center,
0.2,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
Lambertian::new(ConstantTexture::new([
random() * random(),
random() * random(),
random() * random(),
))))),
])),
))
} else if choose_mat < 0.95 {
// metal
Box::new(Sphere::new(
center,
0.2,
Box::new(Metal::new(
Metal::new(
Vec3::new(
0.5 * (1. + random()),
0.5 * (1. + random()),
0.5 * (1. + random()),
),
0.5 * random(),
)),
),
))
} else {
// glass
Box::new(Sphere::new(center, 0.2, Box::new(Dielectric::new(1.5))))
Box::new(Sphere::new(center, 0.2, Dielectric::new(1.5)))
};
objects.push(sphere);
};
@ -116,19 +119,17 @@ fn random_scene(ground_color: Vec3) -> Vec<Box<Hit>> {
Box::new(Sphere::new(
Vec3::new(0., 1., 0.),
1.0,
Box::new(Dielectric::new(1.5)),
Dielectric::new(1.5),
)),
Box::new(Sphere::new(
Vec3::new(-4., 1., 0.),
1.0,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.4, 0.2, 0.1,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.4, 0.2, 0.1))),
)),
Box::new(Sphere::new(
Vec3::new(4., 1., 0.),
1.0,
Box::new(Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0)),
Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0),
)),
];
objects.extend(more);

View File

@ -33,21 +33,17 @@ pub fn new(opt: &Opt) -> Scene {
Box::new(Sphere::new(
Vec3::new(0., 0., -1.),
0.5,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.1, 0.2, 0.5,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))),
)),
Box::new(Sphere::new(
Vec3::new(0., -100.5, -1.),
100.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.8, 0.8, 0.8,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.8, 0.8, 0.8))),
)),
Box::new(Sphere::new(
Vec3::new(1., 0., -1.),
0.5,
Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)),
Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2),
)),
Box::new(MovingSphere::new(
Vec3::new(-1., 0., -1.25),
@ -55,9 +51,7 @@ pub fn new(opt: &Opt) -> Scene {
0.5,
time_min,
time_max,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.2, 0.8, 0.2,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.8, 0.2))),
)),
],
time_min,

View File

@ -1,3 +1,5 @@
use std::sync::Arc;
use camera::Camera;
use cuboid::Cuboid;
use flip_normals::FlipNormals;
@ -38,43 +40,41 @@ pub fn new(opt: &Opt) -> Scene {
let objects: Vec<Box<Hit>> = vec![
// Box1
Box::new(Translate::new(
Box::new(RotateY::new(
Box::new(Cuboid::new(
RotateY::new(
Cuboid::new(
Vec3::new(0., 0., 0.),
Vec3::new(165., 165., 165.),
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
Arc::new(Lambertian::new(ConstantTexture::new(Vec3::new(
0.73, 0.73, 0.73,
))))),
)),
)))),
),
-18.,
)),
),
Vec3::new(100., 0., 0.),
)),
// Box2
Box::new(Translate::new(
Box::new(RotateY::new(
Box::new(Cuboid::new(
RotateY::new(
Cuboid::new(
Vec3::new(0., 0., 0.),
Vec3::new(165., 330., 165.),
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
Arc::new(Lambertian::new(ConstantTexture::new(Vec3::new(
0.73, 0.73, 0.73,
))))),
)),
)))),
),
15.,
)),
),
Vec3::new(265., 0., 295.),
)),
// Green wall left
Box::new(FlipNormals::new(Box::new(YZRect::new(
Box::new(FlipNormals::new(YZRect::new(
0.,
555.,
0.,
555.,
555.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.12, 0.45, 0.15,
))))),
)))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.12, 0.45, 0.15))),
))),
// Red floor right
Box::new(YZRect::new(
0.,
@ -82,9 +82,7 @@ pub fn new(opt: &Opt) -> Scene {
0.,
555.,
0.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.65, 0.05, 0.05,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.65, 0.05, 0.05))),
)),
// Light in ceiling
Box::new(XZRect::new(
@ -93,21 +91,17 @@ pub fn new(opt: &Opt) -> Scene {
227.,
332.,
554.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(15., 15., 15.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(15., 15., 15.))),
)),
// Grey ceiling
Box::new(FlipNormals::new(Box::new(XZRect::new(
Box::new(FlipNormals::new(XZRect::new(
0.,
555.,
0.,
555.,
555.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.73, 0.73, 0.73,
))))),
)))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.73, 0.73, 0.73))),
))),
// Grey floor
Box::new(XZRect::new(
0.,
@ -115,21 +109,17 @@ pub fn new(opt: &Opt) -> Scene {
0.,
555.,
0.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.73, 0.73, 0.73,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.73, 0.73, 0.73))),
)),
// Grey back wall
Box::new(FlipNormals::new(Box::new(XYRect::new(
Box::new(FlipNormals::new(XYRect::new(
0.,
555.,
0.,
555.,
555.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.73, 0.73, 0.73,
))))),
)))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.73, 0.73, 0.73))),
))),
];
let world: Box<Hit> = if opt.use_accel {
Box::new(KDTree::new(objects, time_min, time_max))

View File

@ -45,17 +45,13 @@ pub fn new(opt: &Opt) -> Scene {
let it = ImageTexture::new(image::load_from_memory(world_image_bytes).unwrap().to_rgb());
let objects: Vec<Box<Hit>> = vec![
// Big sphere
Box::new(Sphere::new(
Vec3::new(0., 2., 0.),
2.0,
Box::new(Lambertian::new(Box::new(it))),
)),
Box::new(Sphere::new(Vec3::new(0., 2., 0.), 2.0, Lambertian::new(it))),
// Earth sized sphere
Box::new(Sphere::new(
Vec3::new(0., -1000., 0.),
1000.,
// Box::new(Lambertian::new(ground_color)),
Box::new(Lambertian::new(Box::new(NoiseTexture::with_scale(10.)))),
Lambertian::new(NoiseTexture::with_scale(10.)),
)),
Box::new(XZRect::new(
-100.,
@ -63,9 +59,7 @@ pub fn new(opt: &Opt) -> Scene {
-100.,
1000.,
60.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(1., 1., 1.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 1., 1.))),
)),
Box::new(YZRect::new(
1.,
@ -73,9 +67,7 @@ pub fn new(opt: &Opt) -> Scene {
-1.,
1.,
4.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(4., 0., 4.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 0., 4.))),
)),
Box::new(YZRect::new(
1.,
@ -83,9 +75,7 @@ pub fn new(opt: &Opt) -> Scene {
-1.,
1.,
-4.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(0., 4., 0.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 0.))),
)),
Box::new(XZRect::new(
-1.,
@ -93,9 +83,7 @@ pub fn new(opt: &Opt) -> Scene {
-1.,
1.,
6.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(4., 4., 0.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 4., 0.))),
)),
Box::new(XYRect::new(
-1.,
@ -103,9 +91,7 @@ pub fn new(opt: &Opt) -> Scene {
1.,
3.,
-4.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(0., 0., 4.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 0., 4.))),
)),
Box::new(XYRect::new(
-1.,
@ -113,23 +99,21 @@ pub fn new(opt: &Opt) -> Scene {
1.,
3.,
4.,
Box::new(DiffuseLight::new(Box::new(ConstantTexture::new(
Vec3::new(0., 4., 4.),
)))),
DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 4.))),
)),
/*
Box::new(Sphere::new(
Vec3::new(0., 0., 0.),
0.5,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
Box::new(Lambertian::new(ConstantTexture::new(Vec3::new(
0.1, 0.2, 0.5,
))))),
)))),
)),
// Shiny sphere
Box::new(Sphere::new(
Vec3::new(1., 0., 0.),
0.5,
Box::new(Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2)),
Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
)),
Box::new(MovingSphere::new(
Vec3::new(-1., 0., -0.25),
@ -137,9 +121,9 @@ pub fn new(opt: &Opt) -> Scene {
0.5,
0.,
1.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
Lambertian::new(ConstantTexture::new(Vec3::new(
0.2, 0.8, 0.2,
))))),
))),
)),
*/
];

View File

@ -30,9 +30,9 @@ pub fn new(opt: &Opt) -> Scene {
time_max,
);
let ground_color = if opt.use_accel {
Box::new(ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)))
ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))
} else {
Box::new(ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4)))
ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4))
};
let objects: Vec<Box<Hit>> = vec![
@ -40,19 +40,17 @@ pub fn new(opt: &Opt) -> Scene {
Box::new(Sphere::new(
Vec3::new(0., 0., -1.),
0.5,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.1, 0.2, 0.5,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))),
)),
Box::new(Sphere::new(
Vec3::new(0., -100.5, -1.),
100.,
Box::new(Lambertian::new(ground_color)),
Lambertian::new(ground_color),
)),
Box::new(Sphere::new(
Vec3::new(1., 0., -1.),
0.5,
Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)),
Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2),
)),
Box::new(MovingSphere::new(
Vec3::new(-1., 0., -1.25),
@ -60,9 +58,7 @@ pub fn new(opt: &Opt) -> Scene {
0.5,
0.,
1.,
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
0.2, 0.8, 0.2,
))))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.8, 0.2))),
)),
];
let world: Box<Hit> = if opt.use_accel {

View File

@ -8,10 +8,13 @@ use ray::Ray;
use vec3::dot;
use vec3::Vec3;
pub struct Sphere {
pub struct Sphere<M>
where
M: Material,
{
center: Vec3,
radius: f32,
material: Box<Material>,
material: M,
}
pub fn get_sphere_uv(p: Vec3) -> (f32, f32) {
@ -22,17 +25,26 @@ pub fn get_sphere_uv(p: Vec3) -> (f32, f32) {
(u, v)
}
impl Sphere {
pub fn new(center: Vec3, radius: f32, material: Box<Material>) -> Sphere {
impl<M> Sphere<M>
where
M: Material,
{
pub fn new<V>(center: V, radius: f32, material: M) -> Sphere<M>
where
V: Into<Vec3>,
{
Sphere {
center,
center: center.into(),
radius,
material,
}
}
}
impl Hit for Sphere {
impl<M> Hit for Sphere<M>
where
M: Material,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let oc = r.origin - self.center;
let a = dot(r.direction, r.direction);
@ -49,7 +61,7 @@ impl Hit for Sphere {
uv,
p: point,
normal: (point - self.center) / self.radius,
material: &*self.material,
material: &self.material,
});
}
let temp = (-b + (b * b - a * c).sqrt()) / a;
@ -61,7 +73,7 @@ impl Hit for Sphere {
uv,
p: point,
normal: (point - self.center) / self.radius,
material: &*self.material,
material: &self.material,
});
}
}

View File

@ -7,13 +7,19 @@ pub trait Texture: Send + Sync {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3;
}
#[derive(Debug, PartialEq)]
pub struct ConstantTexture {
color: Vec3,
}
impl ConstantTexture {
pub fn new(color: Vec3) -> ConstantTexture {
ConstantTexture { color }
pub fn new<V>(color: V) -> ConstantTexture
where
V: Into<Vec3>,
{
ConstantTexture {
color: color.into(),
}
}
}
@ -23,18 +29,27 @@ impl Texture for ConstantTexture {
}
}
pub struct CheckerTexture {
odd: Box<Texture>,
even: Box<Texture>,
pub struct CheckerTexture<T>
where
T: Texture,
{
odd: T,
even: T,
}
impl CheckerTexture {
pub fn new(odd: Box<Texture>, even: Box<Texture>) -> CheckerTexture {
impl<T> CheckerTexture<T>
where
T: Texture,
{
pub fn new(odd: T, even: T) -> CheckerTexture<T> {
CheckerTexture { odd, even }
}
}
impl Texture for CheckerTexture {
impl<T> Texture for CheckerTexture<T>
where
T: Texture,
{
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
let sines = (10. * p.x).sin() * (10. * p.y).sin() * (10. * p.z).sin();
if sines < 0. {
@ -106,3 +121,16 @@ impl Texture for ImageTexture {
rgb
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn constant_texture_from_array() {
assert_eq!(
ConstantTexture::new(Vec3::new(1., 2., 3.)),
ConstantTexture::new([1., 2., 3.])
);
}
}

View File

@ -4,18 +4,27 @@ use hitable::HitRecord;
use ray::Ray;
use vec3::Vec3;
pub struct Translate {
hitable: Box<Hit>,
pub struct Translate<H>
where
H: Hit,
{
hitable: H,
offset: Vec3,
}
impl Translate {
pub fn new(hitable: Box<Hit>, offset: Vec3) -> Translate {
impl<H> Translate<H>
where
H: Hit,
{
pub fn new(hitable: H, offset: Vec3) -> Translate<H> {
Translate { hitable, offset }
}
}
impl Hit for Translate {
impl<H> Hit for Translate<H>
where
H: Hit,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let moved_r = Ray::new(r.origin - self.offset, r.direction, r.time);
if let Some(rec) = self.hitable.hit(moved_r, t_min, t_max) {

View File

@ -1,3 +1,4 @@
use std::convert::From;
use std::fmt;
use std::num::ParseFloatError;
use std::ops::Add;
@ -49,6 +50,16 @@ impl Vec3 {
}
}
impl From<[f32; 3]> for Vec3 {
fn from(v: [f32; 3]) -> Self {
Vec3 {
x: v[0],
y: v[1],
z: v[2],
}
}
}
impl fmt::Display for Vec3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {}", self.x, self.y, self.z)