-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Daniel Oom
committed
Aug 10, 2024
1 parent
913386d
commit 561596e
Showing
11 changed files
with
220 additions
and
174 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
[package] | ||
name = "kdtree-tester" | ||
name = "kdtree-tester-cli" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
|
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
use clap::{Parser, Subcommand}; | ||
use kdtree::{sah::SahCost, MAX_DEPTH}; | ||
use ray_tester::kdtree_ray_tester; | ||
use reducer::kdtree_reduce; | ||
use size::Size; | ||
|
||
mod checked_intersection; | ||
mod ray_bouncer; | ||
mod ray_tester; | ||
mod reducer; | ||
mod size; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(version, about, long_about = None)] | ||
struct Cli { | ||
#[command(subcommand)] | ||
command: Commands, | ||
} | ||
|
||
#[derive(Subcommand, Debug)] | ||
enum Commands { | ||
/// Compare kdtree intersection with naive intersection | ||
Test { | ||
/// Wavefront OBJ input path | ||
#[arg(short = 'i', long, required = true)] | ||
input: std::path::PathBuf, | ||
|
||
/// Output ray fail binary data path | ||
#[arg(short = 'o', long)] | ||
output: Option<std::path::PathBuf>, | ||
/// Image size in pixels | ||
#[arg(short, long, default_value_t = Size::new(512, 512))] | ||
size: Size, | ||
/// Max number of bounces to test | ||
#[arg(short, long, default_value_t = 10)] | ||
bounces: u32, | ||
|
||
/// Maximum kd-tree depth | ||
#[arg(long, default_value_t = MAX_DEPTH as u32)] | ||
max_depth: u32, | ||
/// SAH kd-tree traverse cost | ||
#[arg(long, default_value_t = SahCost::default().traverse_cost)] | ||
traverse_cost: f32, | ||
/// SAH kd-tree intersect cost | ||
#[arg(long, default_value_t = SahCost::default().intersect_cost)] | ||
intersect_cost: f32, | ||
/// SAH kd-tree empty factor | ||
#[arg(long, default_value_t = SahCost::default().empty_factor)] | ||
empty_factor: f32, | ||
}, | ||
/// Reduce tree size for a specific intersection error | ||
Reduce { | ||
/// Wavefront OBJ input path | ||
#[arg(short = 'i', long, required = true)] | ||
input: std::path::PathBuf, | ||
|
||
/// Output reduced kd-tree JSON data path | ||
#[arg(short = 'o', long, required = true)] | ||
output: std::path::PathBuf, | ||
|
||
/// Output ray fail binary data path | ||
#[arg(short = 'f', long)] | ||
fail: Option<std::path::PathBuf>, | ||
|
||
/// Seed for random generator used to shuffle input geometry | ||
#[arg(short = 's', long, required = true)] | ||
seed: u64, | ||
}, | ||
} | ||
|
||
fn main() { | ||
let args = Cli::parse(); | ||
match args.command { | ||
Commands::Test { | ||
input, | ||
output, | ||
size, | ||
bounces, | ||
max_depth, | ||
traverse_cost, | ||
intersect_cost, | ||
empty_factor, | ||
} => kdtree_ray_tester( | ||
input, | ||
output, | ||
size, | ||
bounces, | ||
max_depth, | ||
SahCost { | ||
traverse_cost, | ||
intersect_cost, | ||
empty_factor, | ||
}, | ||
), | ||
Commands::Reduce { | ||
input, | ||
output, | ||
fail, | ||
seed, | ||
} => kdtree_reduce(input, output, fail, seed), | ||
} | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
use kdtree::{build::build_kdtree, sah::SahCost}; | ||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; | ||
use scene::{camera::Pinhole, Scene}; | ||
use std::{ | ||
fs::File, | ||
io::{BufWriter, Write}, | ||
path::PathBuf, | ||
}; | ||
|
||
use crate::{ray_bouncer::RayBouncer, size::Size}; | ||
|
||
pub(crate) fn kdtree_ray_tester( | ||
input: PathBuf, | ||
output: Option<PathBuf>, | ||
size: Size, | ||
bounces: u32, | ||
max_depth: u32, | ||
sah: SahCost, | ||
) { | ||
let scene = Scene::read_obj_file_with_print_logging(&input); | ||
|
||
println!("Building kdtree..."); | ||
let kdtree = build_kdtree(&scene.geometries, max_depth, &sah); | ||
|
||
println!("Testing up to {} rays...", size.x * size.y * bounces); | ||
let camera = Pinhole::new(scene.cameras[0].clone(), size.as_uvec2()); | ||
let bouncer = RayBouncer { | ||
scene, | ||
kdtree, | ||
camera, | ||
size: size.as_uvec2(), | ||
bounces, | ||
}; | ||
|
||
let xs = 0..size.x; | ||
let ys = 0..size.y; | ||
let pixels = ys | ||
.flat_map(|y| xs.clone().map(move |x| (x, y))) | ||
.collect::<Vec<_>>(); | ||
let pixel_count = pixels.len(); | ||
let fails = pixels | ||
.into_par_iter() | ||
.enumerate() | ||
.filter_map(|(i, pixel)| { | ||
let result = bouncer.bounce_pixel(pixel); | ||
if let Some(fail) = &result { | ||
eprintln!( | ||
"Fail on pixel {} x {} ({} / {})", | ||
pixel.0, pixel.1, i, pixel_count | ||
); | ||
eprintln!(" {:?}", fail.ray); | ||
eprintln!(" Expected: {:?}", fail.reference); | ||
eprintln!(" Actual: {:?}", fail.kdtree); | ||
} | ||
result | ||
}) | ||
.collect::<Vec<_>>(); | ||
println!("Found {} fails", fails.len()); | ||
|
||
if let Some(path) = output { | ||
println!("Writing failed rays to {:?}...", path); | ||
let mut logger = BufWriter::new(File::create(path).unwrap()); | ||
fails.iter().enumerate().for_each(|(i, fail)| { | ||
logger.write_all(&fail.as_bytes(i as u16)).unwrap(); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use std::{fmt::Display, str::FromStr}; | ||
|
||
use glam::UVec2; | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub(crate) struct Size { | ||
pub(crate) x: u32, | ||
pub(crate) y: u32, | ||
} | ||
|
||
impl Size { | ||
pub(crate) fn new(x: u32, y: u32) -> Self { | ||
Size { x, y } | ||
} | ||
|
||
pub(crate) fn as_uvec2(self) -> UVec2 { | ||
UVec2::new(self.x, self.y) | ||
} | ||
} | ||
|
||
impl FromStr for Size { | ||
type Err = <u32 as FromStr>::Err; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
let pos = s.find('x').expect("Could not parse"); | ||
Ok(Size { | ||
x: s[0..pos].parse()?, | ||
y: s[pos + 1..].parse()?, | ||
}) | ||
} | ||
} | ||
|
||
impl Display for Size { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(f, "{}x{}", self.x, self.y) | ||
} | ||
} |
Oops, something went wrong.