Skip to content

Commit

Permalink
started to add adaptive sampling
Browse files Browse the repository at this point in the history
  • Loading branch information
scott223 committed Dec 2, 2023
1 parent 2fdb4ef commit dd0d328
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 51 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ Simple Raytracer for simple 3D scenes, made in Rust. Objective is to learn Rust,

## Rust learnings applied
- modules, imports, external crates
- borrow, explicit lifetimes
- custom types
- ownership/references/borrow, explicit lifetimes
- methods, enums, structs
- generic methods
- Traits
- iterators, match statement
- basic iterators, match statement
- Result, Error, Option
- reading files, saving files
- logging, .env
Expand Down
4 changes: 2 additions & 2 deletions input/config.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"img_width": 1200.0,
"img_height": 1200.0,
"samples": 2048,
"max_depth": 12,
"samples": 6,
"max_depth": 6,
"sky_color": {
"r": 0.3,
"g": 0.5,
Expand Down
18 changes: 1 addition & 17 deletions input/scene.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,9 @@
"camera_focus_dist": 800.0
},
"elements": [
{
"JSONSphere": {
"center": {
"x": 420,
"y": 60,
"z": 100.0
},
"radius": 60,
"material": {
"Dielectric": {
"index_of_refraction": 1.5
}
},
"attractor": true
}
},
{
"JSONObj": {
"filepath": "input/obj/dragon.obj",
"filepath": "input/obj/teapot.obj",
"material": {
"Lambertian": {
"albedo": {
Expand Down
108 changes: 79 additions & 29 deletions src/render/integrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct RenderIntegrator {
json_scene: JSONScene,
config: Config,
pixels: Vec<Color>,
sample_pixels: Vec<Color>,
filter: Filter,
}

Expand All @@ -40,12 +41,16 @@ impl RenderIntegrator {
let pixels =
vec![Color::new(0.0, 0.0, 0.0); (config.img_width * config.img_height) as usize];

let sample_pixels =
vec![Color::new(0.0, 0.0, 0.0); (config.img_width * config.img_height) as usize];

let filter: Filter = Filter::MitchellNetravali(MitchellNetravali::new(config.pixel_radius, config.pixel_radius, 1./3., 1./3.));

RenderIntegrator {
json_scene,
config,
pixels,
sample_pixels,
filter,
}
}
Expand Down Expand Up @@ -106,6 +111,42 @@ impl RenderIntegrator {
let data = raw_pixels; // An array containing a RGB sequence
writer.write_image_data(&data).unwrap(); // Save

// Sample image

let mut raw_pixels: Vec<u8> = Vec::new();

for p in &self.sample_pixels {
let rgb = p.to_rgb();
raw_pixels.push(rgb.r);
raw_pixels.push(rgb.g);
raw_pixels.push(rgb.b);
}

let path = Path::new("samples.png");
let file = File::create(path).unwrap();
let w = &mut BufWriter::new(file);

let mut encoder = png::Encoder::new(
w,
self.config.img_width as u32,
self.config.img_height as u32,
); // Width x heigth
encoder.set_color(png::ColorType::Rgb);
encoder.set_depth(png::BitDepth::Eight);
encoder.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2)); // 1.0 / 2.2, unscaled, but rounded
let source_chromaticities = png::SourceChromaticities::new(
// Using unscaled instantiation here
(0.31270, 0.32900),
(0.64000, 0.33000),
(0.30000, 0.60000),
(0.15000, 0.06000),
);
encoder.set_source_chromaticities(source_chromaticities);
let mut writer = encoder.write_header().unwrap();

let data = raw_pixels; // An array containing a RGB sequence
writer.write_image_data(&data).unwrap(); // Save

Ok(())
}

Expand Down Expand Up @@ -153,6 +194,12 @@ impl RenderIntegrator {
.enumerate()
.collect();

let sample_bands: Vec<(usize, &mut [Color])> = self
.sample_pixels
.chunks_mut(self.config.img_width as usize)
.enumerate()
.collect();

// start the actual render
log::info!("Starting render");
let pb: ProgressBar = ProgressBar::new(self.config.img_height as u64);
Expand All @@ -168,17 +215,25 @@ impl RenderIntegrator {
.progress_chars("#>-"),
);

//let mut sample_pixels: Vec<Color> = Vec::with_capacity((self.config.img_height * self.config.img_width) as usize);

// use Rayon parallel iterator to iterate over the bands and render per line
bands.into_par_iter().for_each(|(i, band)| {
Self::render_line(
&self.filter,
i,
band,
&camera,
&bvh_tree_sah,
&attractors,
&self.config,
);
bands.into_par_iter()
.zip(sample_bands.into_par_iter())
.enumerate()
.for_each(|(i, (band, sample_band))| {

Self::render_line(
&self.filter,
i,
band.1,
sample_band.1,
&camera,
&bvh_tree_sah,
&attractors,
&self.config,
);

pb.inc(1);
});

Expand All @@ -194,21 +249,27 @@ impl RenderIntegrator {
filter: &Filter,
y: usize,
band: &mut [Color],
sample_pixels: &mut [Color],
camera: &Camera,
bvh_tree_sah: &BVH_SAH,
lights: &Vec<&Element>,
config: &Config,
) {
let mut rng: SmallRng = SmallRng::seed_from_u64(y as u64);
//let mut sample_pixels: Vec<Color> = Vec::with_capacity(config.img_width as usize);

for (x, band_item) in band.iter_mut().enumerate().take(config.img_width as usize) {
let max_samples: i32 = config.samples as i32;


for (x, band_item) in band.iter_mut().enumerate() {
// start with black color
let mut color: Color = Color::new(0.0, 0.0, 0.0);
let mut sum_sample_weight: f64 = 0.0;

// sets a pixel to follow and print detailed logs
let _follow_coords: [usize; 2] = [40, 120];
let pixel_num: u32 = (x * y) as u32;
let mut actual_samples: i32 = 0;

// loop through all the anti aliasing samples
for i in 0..config.samples {
Expand Down Expand Up @@ -237,12 +298,19 @@ impl RenderIntegrator {
&mut rng,
follow,
) * sample_weight;

actual_samples += 1;
}

// set pixel color, but first divide by the number of samples to get the average and return
*band_item = (color / sum_sample_weight)
.clamp()
.linear_to_gamma(2.5);

let factor: f64 = actual_samples as f64 / max_samples as f64;
sample_pixels[x] = Color::new(factor as f64 * 1.0, (1.0-factor) * 1.0, 0.0);


}
}

Expand Down Expand Up @@ -377,21 +445,3 @@ impl RenderIntegrator {
}
}
}

#[cfg(test)]
mod tests {
//use crate::config::Config;
//use crate::config::Scene;

use std::error::Error;

#[test_log::test]
fn test_render_full_scene() -> Result<(), Box<dyn Error>> {
//TODO: test and default for config and scene

//let _config: Config = Config::default();
//let _scene: Scene = Scene::default();
//render(scene, config)?;
Ok(())
}
}

0 comments on commit dd0d328

Please sign in to comment.