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 hitable::Hit;
|
||||||
use ray::Ray;
|
use ray::Ray;
|
||||||
use scenes;
|
use scenes;
|
||||||
|
use texture::EnvMap;
|
||||||
|
use texture::Texture;
|
||||||
use vec3::Vec3;
|
use vec3::Vec3;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -115,32 +117,47 @@ pub struct Scene {
|
|||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub global_illumination: bool,
|
pub global_illumination: bool,
|
||||||
|
pub env_map: Option<EnvMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// color will trace ray up to 50 bounces deep accumulating color as it goes. If
|
// 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
|
// 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.
|
// 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) {
|
if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) {
|
||||||
let (u, v) = rec.uv;
|
let (u, v) = rec.uv;
|
||||||
let emitted = rec.material.emitted(u, v, rec.p);
|
let emitted = rec.material.emitted(u, v, rec.p);
|
||||||
let scatter_response = rec.material.scatter(&r, &rec);
|
let scatter_response = rec.material.scatter(&r, &rec);
|
||||||
if depth < 50 && scatter_response.reflected {
|
if depth < 50 && scatter_response.reflected {
|
||||||
return emitted + scatter_response.attenutation * color(
|
return emitted
|
||||||
scatter_response.scattered,
|
+ scatter_response.attenutation
|
||||||
world,
|
* color(
|
||||||
depth + 1,
|
scatter_response.scattered,
|
||||||
global_illumination,
|
world,
|
||||||
);
|
depth + 1,
|
||||||
|
global_illumination,
|
||||||
|
env_map,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return emitted;
|
return emitted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if global_illumination {
|
if global_illumination {
|
||||||
// No hit, choose color from background.
|
return match env_map {
|
||||||
let unit_direction = r.direction.unit_vector();
|
Some(env_map) => env_map.color(r.direction.unit_vector()),
|
||||||
let t = 0.5 * (unit_direction.y + 1.);
|
None => {
|
||||||
return Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t;
|
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.
|
// No global illumination, so background is black.
|
||||||
Vec3::new(0., 0., 0.)
|
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 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 v = (rng.gen_range::<f32>(0., 1.) + y as f32) / scene.height as f32;
|
||||||
let ray = scene.camera.get_ray(u, v);
|
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(
|
fn render_worker(
|
||||||
|
|||||||
@ -72,5 +72,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use renderer::Scene;
|
|||||||
use sphere::Sphere;
|
use sphere::Sphere;
|
||||||
use texture::CheckerTexture;
|
use texture::CheckerTexture;
|
||||||
use texture::ConstantTexture;
|
use texture::ConstantTexture;
|
||||||
|
use texture::EnvMap;
|
||||||
use vec3::Vec3;
|
use vec3::Vec3;
|
||||||
|
|
||||||
pub fn new(opt: &Opt) -> Scene {
|
pub fn new(opt: &Opt) -> Scene {
|
||||||
@ -44,6 +45,8 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
} else {
|
} else {
|
||||||
Box::new(HitableList::new(random_scene(ground_color)))
|
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 {
|
Scene {
|
||||||
camera,
|
camera,
|
||||||
world,
|
world,
|
||||||
@ -51,6 +54,7 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
env_map: Some(EnvMap::new(skybox)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -66,5 +66,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,5 +133,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,5 +118,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -169,5 +169,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,5 +69,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
global_illumination: true,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -145,5 +145,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: false,
|
global_illumination: false,
|
||||||
|
env_map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,5 +73,6 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
width: opt.width,
|
width: opt.width,
|
||||||
height: opt.height,
|
height: opt.height,
|
||||||
global_illumination: true,
|
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 texture::Texture;
|
||||||
use vec3::Vec3;
|
use vec3::Vec3;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ImageTexture {
|
pub struct ImageTexture {
|
||||||
img: RgbImage,
|
img: RgbImage,
|
||||||
width: f32,
|
width: f32,
|
||||||
|
|||||||
@ -2,8 +2,10 @@ mod checker;
|
|||||||
mod constant;
|
mod constant;
|
||||||
mod image;
|
mod image;
|
||||||
mod noise;
|
mod noise;
|
||||||
|
mod envmap;
|
||||||
pub use texture::checker::CheckerTexture;
|
pub use texture::checker::CheckerTexture;
|
||||||
pub use texture::constant::ConstantTexture;
|
pub use texture::constant::ConstantTexture;
|
||||||
|
pub use texture::envmap::EnvMap;
|
||||||
pub use texture::image::ImageTexture;
|
pub use texture::image::ImageTexture;
|
||||||
pub use texture::noise::NoiseTexture;
|
pub use texture::noise::NoiseTexture;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user