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:
parent
7684bb2088
commit
36b2fba5b7
@ -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.,
|
||||
|
||||
@ -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),
|
||||
))),
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -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))]
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -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))),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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,
|
||||
))))),
|
||||
))),
|
||||
)),
|
||||
*/
|
||||
];
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user