142 lines
4.0 KiB
Rust
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
|
|
}
|