Add environment mapping for background.
This commit is contained in:
parent
815e647ad5
commit
ce2d22b0b5
BIN
rtiow/images/envmap.jpg
Normal file
BIN
rtiow/images/envmap.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 MiB |
@ -19,6 +19,8 @@ use camera::Camera;
|
||||
use hitable::Hit;
|
||||
use ray::Ray;
|
||||
use scenes;
|
||||
use texture::EnvMap;
|
||||
use texture::Texture;
|
||||
use vec3::Vec3;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -115,32 +117,47 @@ pub struct Scene {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub global_illumination: bool,
|
||||
pub env_map: Option<EnvMap>,
|
||||
}
|
||||
|
||||
// color will trace ray up to 50 bounces deep accumulating color as it goes. If
|
||||
// global_illumination is true, a default light background color is assumed and will light the
|
||||
// world. If false, it is expected the scene has emissive light sources.
|
||||
fn color(r: Ray, world: &Hit, depth: usize, global_illumination: bool) -> Vec3 {
|
||||
fn color(
|
||||
r: Ray,
|
||||
world: &Hit,
|
||||
depth: usize,
|
||||
global_illumination: bool,
|
||||
env_map: &Option<EnvMap>,
|
||||
) -> Vec3 {
|
||||
if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) {
|
||||
let (u, v) = rec.uv;
|
||||
let emitted = rec.material.emitted(u, v, rec.p);
|
||||
let scatter_response = rec.material.scatter(&r, &rec);
|
||||
if depth < 50 && scatter_response.reflected {
|
||||
return emitted + scatter_response.attenutation * color(
|
||||
scatter_response.scattered,
|
||||
world,
|
||||
depth + 1,
|
||||
global_illumination,
|
||||
);
|
||||
return emitted
|
||||
+ scatter_response.attenutation
|
||||
* color(
|
||||
scatter_response.scattered,
|
||||
world,
|
||||
depth + 1,
|
||||
global_illumination,
|
||||
env_map,
|
||||
);
|
||||
} else {
|
||||
return emitted;
|
||||
}
|
||||
}
|
||||
if global_illumination {
|
||||
// No hit, choose color from background.
|
||||
let unit_direction = r.direction.unit_vector();
|
||||
let t = 0.5 * (unit_direction.y + 1.);
|
||||
return Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t;
|
||||
return match env_map {
|
||||
Some(env_map) => env_map.color(r.direction.unit_vector()),
|
||||
None => {
|
||||
let unit_direction = r.direction.unit_vector();
|
||||
// No hit, choose color from background.
|
||||
let t = 0.5 * (unit_direction.y + 1.);
|
||||
Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t
|
||||
}
|
||||
};
|
||||
}
|
||||
// No global illumination, so background is black.
|
||||
Vec3::new(0., 0., 0.)
|
||||
@ -151,7 +168,13 @@ fn trace_pixel(x: usize, y: usize, scene: &Scene) -> Vec3 {
|
||||
let u = (rng.gen_range::<f32>(0., 1.) + x as f32) / scene.width as f32;
|
||||
let v = (rng.gen_range::<f32>(0., 1.) + y as f32) / scene.height as f32;
|
||||
let ray = scene.camera.get_ray(u, v);
|
||||
color(ray, scene.world.as_ref(), 0, scene.global_illumination)
|
||||
color(
|
||||
ray,
|
||||
scene.world.as_ref(),
|
||||
0,
|
||||
scene.global_illumination,
|
||||
&scene.env_map,
|
||||
)
|
||||
}
|
||||
|
||||
fn render_worker(
|
||||
|
||||
@ -72,5 +72,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ use renderer::Scene;
|
||||
use sphere::Sphere;
|
||||
use texture::CheckerTexture;
|
||||
use texture::ConstantTexture;
|
||||
use texture::EnvMap;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub fn new(opt: &Opt) -> Scene {
|
||||
@ -44,6 +45,8 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
} 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,
|
||||
@ -51,6 +54,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
env_map: Some(EnvMap::new(skybox)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -66,5 +66,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,5 +133,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: false,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,5 +118,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: false,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,5 +169,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: false,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,5 +69,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,5 +145,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: false,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,5 +73,6 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
global_illumination: true,
|
||||
env_map: None,
|
||||
}
|
||||
}
|
||||
|
||||
27
rtiow/src/texture/envmap.rs
Normal file
27
rtiow/src/texture/envmap.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use std::f32;
|
||||
|
||||
use image::RgbImage;
|
||||
|
||||
use texture::ImageTexture;
|
||||
use texture::Texture;
|
||||
use vec3::Vec3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EnvMap {
|
||||
img_tex: ImageTexture,
|
||||
}
|
||||
|
||||
impl EnvMap {
|
||||
pub fn new(img: RgbImage) -> EnvMap {
|
||||
EnvMap {
|
||||
img_tex: ImageTexture::new(img),
|
||||
}
|
||||
}
|
||||
pub fn color(&self, ray: Vec3) -> Vec3 {
|
||||
let zero = Vec3::new(0., 0., 0.);
|
||||
let u = ray.x.atan2(ray.z) / f32::consts::PI /2.0 + 0.5;
|
||||
let v = ray.y / 2.0 + 0.5;
|
||||
// TODO(wathiede): properly wrap sphere to lat/lon.
|
||||
self.img_tex.value(u, v, zero)
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ use image::RgbImage;
|
||||
use texture::Texture;
|
||||
use vec3::Vec3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ImageTexture {
|
||||
img: RgbImage,
|
||||
width: f32,
|
||||
|
||||
@ -2,8 +2,10 @@ mod checker;
|
||||
mod constant;
|
||||
mod image;
|
||||
mod noise;
|
||||
mod envmap;
|
||||
pub use texture::checker::CheckerTexture;
|
||||
pub use texture::constant::ConstantTexture;
|
||||
pub use texture::envmap::EnvMap;
|
||||
pub use texture::image::ImageTexture;
|
||||
pub use texture::noise::NoiseTexture;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user