142 lines
4.0 KiB
Rust

use rand;
use rand::Rng;
use camera::Camera;
use hitable::Hit;
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::EnvMap;
use vec3::Vec3;
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(13., 2., 3.);
let lookat = Vec3::new(0., 0., 0.);
let dist_to_focus = 10.;
let aperture = 0.1;
let time_min = 0.;
let time_max = 1.;
let camera = Camera::new(
lookfrom,
lookat,
Vec3::new(0., 1., 0.),
50.,
opt.width as f32 / opt.height as f32,
aperture,
dist_to_focus,
time_min,
time_max,
);
let ground_color = if opt.use_accel {
[1.0, 0.4, 0.4]
} else {
[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))
} else {
Box::new(HitableList::new(random_scene(ground_color)))
};
let skybox_bytes = include_bytes!("../../images/envmap.jpg");
let skybox = image::load_from_memory(skybox_bytes).unwrap().to_rgb();
Scene {
camera,
world,
subsamples: opt.subsamples,
width: opt.width,
height: opt.height,
global_illumination: true,
env_map: Some(EnvMap::new(skybox)),
}
}
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_material: Box<Material> = if checker {
Box::new(Lambertian::new(CheckerTexture::new(
ConstantTexture::new([0., 0., 0.]),
ConstantTexture::new(ground_color),
)))
} else {
Box::new(Lambertian::new(ConstantTexture::new(ground_color)))
};
let mut objects: Vec<Box<Hit>> = vec![Box::new(Sphere::new(
[0., -1000., 0.],
1000.,
ground_material,
))];
let mut random = || rng.gen_range::<f32>(0., 1.);
for a in -11..11 {
for b in -11..11 {
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: Box<Hit> = if choose_mat < 0.8 {
// diffuse
Box::new(Sphere::new(
center,
0.2,
Lambertian::new(ConstantTexture::new([
random() * random(),
random() * random(),
random() * random(),
])),
))
} else if choose_mat < 0.95 {
// metal
Box::new(Sphere::new(
center,
0.2,
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, Dielectric::new(1.5)))
};
objects.push(sphere);
};
}
}
let more: Vec<Box<Hit>> = vec![
Box::new(Sphere::new(
Vec3::new(0., 1., 0.),
1.0,
Dielectric::new(1.5),
)),
Box::new(Sphere::new(
Vec3::new(-4., 1., 0.),
1.0,
Lambertian::new(ConstantTexture::new(Vec3::new(0.4, 0.2, 0.1))),
)),
Box::new(Sphere::new(
Vec3::new(4., 1., 0.),
1.0,
Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0),
)),
];
objects.extend(more);
objects
}