First version of adaptive subsampling.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Add debugging images, and move rendering to output module.
This commit is contained in:
parent
f0f90a6b80
commit
5d9e180817
19
rtiow/Cargo.lock
generated
19
rtiow/Cargo.lock
generated
@ -96,7 +96,7 @@ dependencies = [
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -428,7 +428,7 @@ dependencies = [
|
||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1566,7 +1566,7 @@ dependencies = [
|
||||
"mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1614,6 +1614,7 @@ dependencies = [
|
||||
"rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stderrlog 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1641,7 +1642,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.7"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -1732,11 +1733,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.38"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1926,7 +1927,7 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2593,7 +2594,7 @@ dependencies = [
|
||||
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
|
||||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56"
|
||||
@ -2606,7 +2607,7 @@ dependencies = [
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850"
|
||||
"checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4"
|
||||
"checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9"
|
||||
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
|
||||
"checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2"
|
||||
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
"checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4"
|
||||
|
||||
@ -20,6 +20,7 @@ num_cpus = "1.8.0"
|
||||
rand = "0.5.5"
|
||||
serde = "1.0.79"
|
||||
serde_derive = "1.0.79"
|
||||
serde_json = "1.0.41"
|
||||
stderrlog = "0.4.1"
|
||||
structopt = "0.2.10"
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ pub mod kdtree;
|
||||
pub mod material;
|
||||
pub mod moving_sphere;
|
||||
pub mod noise;
|
||||
pub mod output;
|
||||
pub mod ray;
|
||||
pub mod rect;
|
||||
pub mod renderer;
|
||||
|
||||
139
rtiow/src/output.rs
Normal file
139
rtiow/src/output.rs
Normal file
@ -0,0 +1,139 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use chrono::Local;
|
||||
use image::RgbImage;
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
|
||||
use crate::vec3::Vec3;
|
||||
|
||||
// Main RGB image output from rendering the scene.
|
||||
pub const MAIN_IMAGE: &str = "@final";
|
||||
// Debug image for adaptive pixels subsampling.
|
||||
// Red indicates recursion hit maximum depth splitting the pixel.
|
||||
// Green indicates no subdivision necessary
|
||||
pub const ADAPTIVE_DEPTH: &str = "adaptive_depth";
|
||||
|
||||
lazy_static! {
|
||||
static ref DEBUGGER: Arc<Mutex<Debugger>> = Arc::new(Mutex::new(Debugger::new()));
|
||||
}
|
||||
|
||||
struct Debugger {
|
||||
images: HashMap<String, RgbImage>,
|
||||
}
|
||||
|
||||
impl Debugger {
|
||||
fn new() -> Debugger {
|
||||
Debugger {
|
||||
images: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_image(name: String, dimensions: (u32, u32)) {
|
||||
let mut debugger = DEBUGGER.lock().unwrap();
|
||||
debugger
|
||||
.images
|
||||
.insert(name, RgbImage::new(dimensions.0, dimensions.1));
|
||||
}
|
||||
|
||||
pub fn set_pixel(name: &str, x: usize, y: usize, pixel: Vec3) {
|
||||
let mut debugger = DEBUGGER.lock().unwrap();
|
||||
let img = debugger
|
||||
.images
|
||||
.get_mut(name)
|
||||
.expect(&format!("couldn't find image named '{}'", name));
|
||||
let y_inv = img.height() - y as u32 - 1;
|
||||
img.put_pixel(
|
||||
x as u32,
|
||||
y_inv as u32,
|
||||
image::Rgb([
|
||||
(pixel[0] * 255.).min(255.) as u8,
|
||||
(pixel[1] * 255.).min(255.) as u8,
|
||||
(pixel[2] * 255.).min(255.) as u8,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn write_images<P: AsRef<Path>>(output_dir: P) -> std::io::Result<()> {
|
||||
let output_dir: &Path = output_dir.as_ref();
|
||||
let debugger = DEBUGGER.lock().unwrap();
|
||||
let now = Local::now();
|
||||
/*
|
||||
let style = r#"
|
||||
<style>
|
||||
.frame {
|
||||
display: inline-block;
|
||||
}
|
||||
figure {
|
||||
margin: 0.25em;
|
||||
}
|
||||
figcaption {
|
||||
text-align: center;
|
||||
}
|
||||
img {
|
||||
max-width: 97%;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
border: 1px solid #999;
|
||||
padding: 5px;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
"#;
|
||||
writeln!(f, "{}", style)?;
|
||||
writeln!(
|
||||
f,
|
||||
"<h1>Run @ {} ({})</h1>",
|
||||
now.to_rfc2822(),
|
||||
now.timestamp()
|
||||
)?;
|
||||
*/
|
||||
// Write out images in consistent order.
|
||||
let mut names = debugger.images.keys().collect::<Vec<_>>();
|
||||
names.sort();
|
||||
let mut ratio = 1.;
|
||||
let mut size = (0, 0);
|
||||
for name in &names {
|
||||
let img = debugger.images.get(*name).unwrap();
|
||||
if *name == MAIN_IMAGE {
|
||||
let (w, h) = img.dimensions();
|
||||
ratio = w as f32 / h as f32;
|
||||
size = img.dimensions();
|
||||
}
|
||||
let filename = format!("{}.png", name);
|
||||
/*
|
||||
writeln!(
|
||||
f,
|
||||
r#"<div class="frame"><figure><a href="{0}?t={2}"><img src="{0}?t={2}"></a><figcaption>{1} ({2})</figcaption></figure></div>"#,
|
||||
filename, name, now.timestamp())?;
|
||||
*/
|
||||
let path = output_dir.join(filename);
|
||||
info!("Saving {}", path.to_string_lossy());
|
||||
img.save(path)?;
|
||||
}
|
||||
let f = File::create(output_dir.join("data.json"))?;
|
||||
#[derive(Serialize)]
|
||||
struct Data {
|
||||
timestamp: i64,
|
||||
ratio: f32,
|
||||
size: (u32, u32),
|
||||
names: Vec<String>,
|
||||
images: Vec<String>,
|
||||
}
|
||||
serde_json::ser::to_writer(
|
||||
f,
|
||||
&Data {
|
||||
timestamp: now.timestamp(),
|
||||
ratio,
|
||||
size,
|
||||
names: names.iter().map(|s| s.to_string()).collect(),
|
||||
images: names.iter().map(|s| format!("{}.png", s)).collect(),
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
use std::fmt;
|
||||
use std::ops::Range;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
@ -13,8 +14,6 @@ use std::sync::Mutex;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
use image;
|
||||
use image::RgbImage;
|
||||
#[cfg(feature = "prom")]
|
||||
use lazy_static::lazy_static;
|
||||
use num_cpus;
|
||||
@ -25,6 +24,7 @@ use crate::camera::Camera;
|
||||
use crate::hitable::Hit;
|
||||
use crate::human;
|
||||
use crate::material::Lambertian;
|
||||
use crate::output;
|
||||
use crate::ray::Ray;
|
||||
use crate::scenes;
|
||||
use crate::sphere::Sphere;
|
||||
@ -150,9 +150,6 @@ pub struct Opt {
|
||||
/// Sub-samples per pixel
|
||||
#[structopt(short = "s", long = "subsample", default_value = "8")]
|
||||
pub subsamples: usize,
|
||||
/// Use adaptive subsampling
|
||||
#[structopt(long = "adaptive")]
|
||||
pub adaptive_subsampling: bool,
|
||||
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box",
|
||||
/// "cornell_smoke", "perlin_debug", "final"
|
||||
#[structopt(long = "model", default_value = "book")]
|
||||
@ -188,7 +185,7 @@ pub struct Scene {
|
||||
pub camera: Camera,
|
||||
pub subsamples: usize,
|
||||
/// overrides subsamples setting.
|
||||
pub adaptive_subsampling: bool,
|
||||
pub adaptive_subsampling: Option<f32>,
|
||||
pub num_threads: Option<usize>,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
@ -223,7 +220,7 @@ impl Default for Scene {
|
||||
)),
|
||||
camera,
|
||||
subsamples: 0,
|
||||
adaptive_subsampling: false,
|
||||
adaptive_subsampling: None,
|
||||
num_threads: None,
|
||||
width: 0,
|
||||
height: 0,
|
||||
@ -278,7 +275,103 @@ fn color(
|
||||
Vec3::new(0., 0., 0.)
|
||||
}
|
||||
|
||||
fn trace_pixel(x: usize, y: usize, scene: &Scene) -> Vec3 {
|
||||
const MAX_ADAPTIVE_DEPTH: usize = 10;
|
||||
fn trace_pixel_adaptive(
|
||||
depth: usize,
|
||||
threshold: f32,
|
||||
x: usize,
|
||||
y: usize,
|
||||
x_range: Range<f32>,
|
||||
y_range: Range<f32>,
|
||||
scene: &Scene,
|
||||
) -> Vec3 {
|
||||
let w = scene.width as f32;
|
||||
let h = scene.height as f32;
|
||||
let x_mid = x_range.start + ((x_range.end - x_range.start) / 2.);
|
||||
let y_mid = y_range.start + ((y_range.end - y_range.start) / 2.);
|
||||
let mc = ((x_mid + x as f32) / w, (y_mid + y as f32) / h);
|
||||
let center = color(
|
||||
scene.camera.get_ray(mc.0, mc.1),
|
||||
scene.world.as_ref(),
|
||||
0,
|
||||
scene.global_illumination,
|
||||
&scene.env_map,
|
||||
);
|
||||
if depth == 0 {
|
||||
output::set_pixel(output::ADAPTIVE_DEPTH, x, y, [1., 0., 0.].into());
|
||||
return center;
|
||||
}
|
||||
// t = top
|
||||
// m = middle
|
||||
// b = bottom
|
||||
// l = left
|
||||
// c = center
|
||||
// r = right
|
||||
let tl = (
|
||||
(x_range.start + x as f32) / w,
|
||||
(y_range.start + y as f32) / h,
|
||||
);
|
||||
let tr = ((x_range.end + x as f32) / w, (y_range.start + y as f32) / h);
|
||||
let bl = ((x_range.start + x as f32) / w, (y_range.end + y as f32) / h);
|
||||
let br = ((x_range.end + x as f32) / w, (y_range.end + y as f32) / h);
|
||||
|
||||
let corners = [tl, tr, mc, bl, br]
|
||||
.iter()
|
||||
.map(|(u, v)| {
|
||||
color(
|
||||
scene.camera.get_ray(*u, *v),
|
||||
scene.world.as_ref(),
|
||||
0,
|
||||
scene.global_illumination,
|
||||
&scene.env_map,
|
||||
)
|
||||
})
|
||||
.fold([0., 0., 0.].into(), |a: Vec3, b: Vec3| a + b)
|
||||
/ 5.;
|
||||
if (corners - center).length() > threshold {
|
||||
let pixel = (trace_pixel_adaptive(
|
||||
depth - 1,
|
||||
threshold,
|
||||
x,
|
||||
y,
|
||||
x_range.start..x_mid,
|
||||
y_range.start..y_mid,
|
||||
scene,
|
||||
) + trace_pixel_adaptive(
|
||||
depth - 1,
|
||||
threshold,
|
||||
x,
|
||||
y,
|
||||
x_mid..x_range.end,
|
||||
y_range.start..y_mid,
|
||||
scene,
|
||||
) + trace_pixel_adaptive(
|
||||
depth - 1,
|
||||
threshold,
|
||||
x,
|
||||
y,
|
||||
x_range.start..x_mid,
|
||||
y_mid..y_range.end,
|
||||
scene,
|
||||
) + trace_pixel_adaptive(
|
||||
depth - 1,
|
||||
threshold,
|
||||
x,
|
||||
y,
|
||||
x_mid..x_range.end,
|
||||
y_mid..y_range.end,
|
||||
scene,
|
||||
)) / 4.;
|
||||
pixel
|
||||
} else {
|
||||
if depth == MAX_ADAPTIVE_DEPTH {
|
||||
output::set_pixel(output::ADAPTIVE_DEPTH, x, y, [0., 1., 0.].into());
|
||||
}
|
||||
corners
|
||||
}
|
||||
}
|
||||
|
||||
fn trace_pixel_random(x: usize, y: usize, scene: &Scene) -> Vec3 {
|
||||
let mut rng = rand::thread_rng();
|
||||
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;
|
||||
@ -306,17 +399,25 @@ static PIXEL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn render_pixel(scene: &Scene, x: usize, y: usize) -> Vec3 {
|
||||
let mut pixel: Vec3 = Default::default();
|
||||
let pixel = if scene.adaptive_subsampling {
|
||||
Default::default()
|
||||
let pixel = if let Some(threshold) = scene.adaptive_subsampling {
|
||||
trace_pixel_adaptive(
|
||||
MAX_ADAPTIVE_DEPTH,
|
||||
threshold,
|
||||
x,
|
||||
y,
|
||||
0.0..1.0,
|
||||
0.0..1.0,
|
||||
scene,
|
||||
)
|
||||
} else {
|
||||
for _ in 0..scene.subsamples {
|
||||
pixel = pixel + trace_pixel(x, y, scene);
|
||||
pixel = pixel + trace_pixel_random(x, y, scene);
|
||||
}
|
||||
pixel / scene.subsamples as f32
|
||||
};
|
||||
PIXEL_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||
// Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 or
|
||||
// sqrt.
|
||||
PIXEL_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||
Vec3::new(pixel[0].sqrt(), pixel[1].sqrt(), pixel[2].sqrt())
|
||||
}
|
||||
|
||||
@ -361,7 +462,7 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
||||
let scene = Arc::new(scene);
|
||||
let pixel_req_rx = Arc::new(Mutex::new(pixel_req_rx));
|
||||
info!("Creating {} render threads", num_threads);
|
||||
info!("Adaptive subsampling: {}", scene.adaptive_subsampling);
|
||||
info!("Adaptive subsampling: {:?}", scene.adaptive_subsampling);
|
||||
for i in 0..num_threads {
|
||||
let s = sync::Arc::clone(&scene);
|
||||
let pixel_req_rx = pixel_req_rx.clone();
|
||||
@ -394,6 +495,18 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
||||
drop(pixel_req_tx);
|
||||
});
|
||||
|
||||
info!("Rendering with {} subsamples", scene.subsamples);
|
||||
output::register_image(
|
||||
output::MAIN_IMAGE.to_string(),
|
||||
(scene.width as u32, scene.height as u32),
|
||||
);
|
||||
if scene.adaptive_subsampling.is_some() {
|
||||
output::register_image(
|
||||
output::ADAPTIVE_DEPTH.to_string(),
|
||||
(scene.width as u32, scene.height as u32),
|
||||
);
|
||||
}
|
||||
|
||||
let pixel_total = scene.width * scene.height;
|
||||
thread::spawn(move || {
|
||||
let mut last_time = time::Instant::now();
|
||||
@ -423,40 +536,17 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i
|
||||
}
|
||||
});
|
||||
|
||||
info!("Rendering with {} subsamples", scene.subsamples);
|
||||
let mut img = RgbImage::new(scene.width as u32, scene.height as u32);
|
||||
for resp in pixel_resp_rx {
|
||||
match resp {
|
||||
Response::Pixel { x, y, pixel } => {
|
||||
let y_inv = scene.height - y - 1;
|
||||
img.put_pixel(
|
||||
x as u32,
|
||||
y_inv as u32,
|
||||
image::Rgb([
|
||||
(pixel[0] * 255.).min(255.) as u8,
|
||||
(pixel[1] * 255.).min(255.) as u8,
|
||||
(pixel[2] * 255.).min(255.) as u8,
|
||||
]),
|
||||
);
|
||||
output::set_pixel(output::MAIN_IMAGE, x, y, pixel);
|
||||
}
|
||||
Response::Line { y, pixels } => {
|
||||
for (x, pixel) in pixels.iter().enumerate() {
|
||||
let y_inv = scene.height - y - 1;
|
||||
img.put_pixel(
|
||||
x as u32,
|
||||
y_inv as u32,
|
||||
image::Rgb([
|
||||
(pixel[0] * 255.).min(255.) as u8,
|
||||
(pixel[1] * 255.).min(255.) as u8,
|
||||
(pixel[2] * 255.).min(255.) as u8,
|
||||
]),
|
||||
);
|
||||
output::set_pixel(output::MAIN_IMAGE, x, y, *pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let path = output_dir.join("final.png");
|
||||
// Write the contents of this image to the Writer in PNG format.
|
||||
trace!(target: "renderer", "Saving {}", path.display());
|
||||
img.save(path)
|
||||
output::write_images(output_dir)
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
camera,
|
||||
world,
|
||||
subsamples: opt.subsamples,
|
||||
adaptive_subsampling: opt.adaptive_subsampling,
|
||||
adaptive_subsampling: Some(0.5),
|
||||
num_threads: opt.num_threads,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::camera::Camera;
|
||||
use crate::hitable::Hit;
|
||||
use crate::hitable_list::HitableList;
|
||||
use crate::kdtree::KDTree;
|
||||
use crate::material::Dielectric;
|
||||
use crate::material::Lambertian;
|
||||
use crate::material::Metal;
|
||||
use crate::moving_sphere::MovingSphere;
|
||||
@ -12,7 +13,7 @@ use crate::texture::ConstantTexture;
|
||||
use crate::vec3::Vec3;
|
||||
|
||||
pub fn new(opt: &Opt) -> Scene {
|
||||
let lookfrom = Vec3::new(3., 3., 2.);
|
||||
let lookfrom = Vec3::new(3., 2., 2.);
|
||||
let lookat = Vec3::new(0., 0., -1.);
|
||||
let dist_to_focus = (lookfrom - lookat).length();
|
||||
let aperture = 0.1;
|
||||
@ -37,6 +38,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
|
||||
let objects: Vec<Box<dyn Hit>> = vec![
|
||||
//let world: Box<Hit> = Box::new(HitableList::new(vec![
|
||||
Box::new(Sphere::new([1., 0., 0.], 0.5, Dielectric::new(1.5))),
|
||||
Box::new(Sphere::new(
|
||||
Vec3::new(0., 0., -1.),
|
||||
0.5,
|
||||
@ -70,6 +72,8 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
camera,
|
||||
world,
|
||||
subsamples: opt.subsamples,
|
||||
// adaptive_subsampling: None,
|
||||
adaptive_subsampling: Some(0.5),
|
||||
num_threads: opt.num_threads,
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user