Skip to content

Commit

Permalink
added .env
Browse files Browse the repository at this point in the history
  • Loading branch information
scott223 committed Nov 13, 2023
1 parent 5a9e2ae commit c8163ab
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 74 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
RUST_LOG=info
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.105"
png = "0.17.10"
wavefront_obj = "10.0.0"
dotenv = "0.15.0"

[dev-dependencies]
test-log = "0.2.12"
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Default for Config {
}
}

#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JSONScene {
pub camera: JSONCamera,
pub elements: Vec<JSONElement>,
Expand Down
77 changes: 18 additions & 59 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,37 @@
use dotenv::dotenv;
use std::env;
use std::fs::File;
use std::io::{BufReader, BufWriter};
use std::path::Path;

use raytracer::render::integrator::RenderIntegrator;
use raytracer::render::RenderIntegrator;

// App main function
// load the JSON files for the Scene and for the Configuration, and calls the main raytracer function render from lib.rsß
// load the JSON files for the Scene and for the Configuration, and calls the main raytracer function render from lib.rs
fn main() {
dotenv().ok();

env_logger::init();

log::info!(
"Program started: loading scene and config from JSON files located in /input and render will be located in /render. Base directory is {:?}",
env::current_dir().unwrap()
);

// Open the Scene file
let scene_file =
File::open("input/scene.json").expect("Error reading input/scene.json, quitting");
let scene_reader = BufReader::new(scene_file);

// Read the JSON contents of the file as an instance of `Scene`.
let scene: raytracer::config::JSONScene =
serde_json::from_reader(scene_reader).expect("Error parsing input/scene.json, quitting");

// Open the Config file
let config_file =
File::open("input/config.json").expect("Error reading input/config.json, quitting");
let config_reader = BufReader::new(config_file);

// Read the JSON contents of the file as an instance of `Config`.
let config: raytracer::config::Config =
serde_json::from_reader(config_reader).expect("Error parsing input/config.json, quitting");

let r: RenderIntegrator = RenderIntegrator::new(scene, config);
let mut r: RenderIntegrator = RenderIntegrator::new_from_json("input/scene.json", "input/config.json");

// execute the main render
match r.render() {
Ok(i) => {
//i.save("renders/render.png").unwrap();

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

for p in i {
let rgb = p.to_rgb();
raw_pixels.push(rgb.r);
raw_pixels.push(rgb.g);
raw_pixels.push(rgb.b);
Ok(()) => {

// success, so save to png
match r.save_to_png("renders/render.png") {
Ok(()) => {
log::info!("File saved, closing program");
}
Err(e) => {
log::error!("Error in saving file: {}", e);
}
}

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

let mut encoder =
png::Encoder::new(w, config.img_width as u32, 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
log::info!("File saved, closing program");
}
Err(e) => {
panic!("Error in render function: {}", e);
log::error!("Error in render function: {}", e);
}
}
} //fn main
2 changes: 1 addition & 1 deletion src/render/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};

use crate::{config::Config, linalg::Vec3, render::ray::Ray};

#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub struct JSONCamera {
pub camera_center: Vec3,
pub camera_look_at: Vec3,
Expand Down
87 changes: 75 additions & 12 deletions src/render/integrator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{error::Error, time::Instant};
use std::{error::Error, time::Instant, fs::File, io::{BufReader, BufWriter}, path::Path};

use indicatif::ProgressBar;
use rand::{rngs::SmallRng, SeedableRng};
Expand All @@ -16,28 +16,94 @@ use crate::{
render::ray::Ray,
};

#[derive(Debug, Clone)]
pub struct RenderIntegrator {
json_scene: JSONScene,
config: Config,
pixels: Vec<Color>,
}

impl RenderIntegrator {
pub fn new(json_scene: JSONScene, config: Config) -> Self {
RenderIntegrator { json_scene, config }
// create a 1-d vector holding all the pixels, and
let pixels = vec![
Color::new(0.0, 0.0, 0.0);
(config.img_width * config.img_height) as usize
];

RenderIntegrator { json_scene, config, pixels }
}

pub fn new_from_json(scene_path: &str, config_path: &str) -> Self {

// Open the Scene file
let scene_file =
File::open(scene_path).expect("Error reading input/scene.json, quitting");
let scene_reader = BufReader::new(scene_file);

// Read the JSON contents of the file as an instance of `Scene`.
let scene: JSONScene =
serde_json::from_reader(scene_reader).expect("Error parsing input/scene.json, quitting");

// Open the Config file
let config_file =
File::open(config_path).expect("Error reading input/config.json, quitting");
let config_reader = BufReader::new(config_file);

// Read the JSON contents of the file as an instance of `Config`.
let config: Config =
serde_json::from_reader(config_reader).expect("Error parsing input/config.json, quitting");

return RenderIntegrator::new(scene, config);
}

pub fn save_to_png(&self, png_path: &str) -> Result<(), Box<dyn Error>> {
let mut raw_pixels: Vec<u8> = Vec::new();

for p in &self.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(png_path);
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(())
}

// fn render
// the main render function that sets up the camera, creates an 1d vector for the pixels, splits it into bands, calls the band render function and writes to an image file
// applies parallel rendering using Rayon
pub fn render(self) -> Result<Vec<Color>, Box<dyn Error>> {
pub fn render(&mut self) -> Result<(), Box<dyn Error>> {
// create a new camera object
let camera: Camera = Camera::new(&self.config, &self.json_scene.camera);

// we loop through the JSON Scene, and create a new actual object for each simplified JSON object
// this allows us to pre-calculate various things like the bbox or commonly used numbers in the cconstructor
let mut objects: Vec<Element> = Vec::new();

for json_element in self.json_scene.elements {
for json_element in &self.json_scene.elements {
match json_element {
JSONElement::JSONQuad(q) => q.add_as_element(&mut objects),
JSONElement::JSONSphere(s) => s.add_as_element(&mut objects),
Expand All @@ -56,12 +122,9 @@ impl RenderIntegrator {
// create a refrence to the elements that are marked as an attractor
let attractors: Vec<&Element> = objects.iter().filter(|e| e.is_attractor()).collect();

// create a 1-d vector holding all the pixels, and split into bands for parallel rendering
let mut pixels = vec![
Color::new(0.0, 0.0, 0.0);
(self.config.img_width * self.config.img_height) as usize
];
let bands: Vec<(usize, &mut [Color])> = pixels
// split into bands for parallel rendering

let bands: Vec<(usize, &mut [Color])> = self.pixels
.chunks_mut(self.config.img_width as usize)
.enumerate()
.collect();
Expand All @@ -86,8 +149,8 @@ impl RenderIntegrator {

log::info!("Render finished in {}ms", start.elapsed().as_millis());

// return the pixels
Ok(pixels)
// return an OK
Ok(())
}

// fn render_line
Expand Down
3 changes: 2 additions & 1 deletion src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod camera;
pub mod integrator;
mod integrator;
pub use integrator::RenderIntegrator;

mod pdf;
pub use pdf::{CosinePDF, HittablePDF, MixedPDF, PDFTrait, Pdf};
Expand Down

0 comments on commit c8163ab

Please sign in to comment.