Add eval to visualizer and fix pbr error

This commit is contained in:
hal8174 2024-12-26 00:57:57 +01:00
parent 109a72c19a
commit 3a37a72f56
10 changed files with 105 additions and 55 deletions

4
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "ab_glyph" name = "ab_glyph"
@ -2205,7 +2205,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "ray-tracing-material-validator" name = "ray-tracing-material-visualizer"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"plotters", "plotters",

View file

@ -8,7 +8,7 @@ pub trait Material<R: Rng>: Sync + Debug {
fn sample(&self, w_in: Dir3, rng: &mut R) -> SampleResult { fn sample(&self, w_in: Dir3, rng: &mut R) -> SampleResult {
let w_out = Dir3::sample_cosine_hemisphere(rng); let w_out = Dir3::sample_cosine_hemisphere(rng);
SampleResult::new(w_out, self.eval(w_in, w_out, rng)) SampleResult::new(w_out, self.eval(w_in, w_out, rng) * FloatConsts::PI)
} }
} }

View file

@ -68,6 +68,13 @@ impl Dir3 {
Dir3::new(Float::sin(phi) * r, Float::cos(theta), Float::cos(phi) * r) Dir3::new(Float::sin(phi) * r, Float::cos(theta), Float::cos(phi) * r)
} }
pub fn sample_uniform_sphere<R: Rng>(rng: &mut R) -> Self {
let theta = Float::acos(1.0 - 2.0 * rng.gen::<Float>());
let phi = 2.0 * FloatConsts::PI * rng.gen::<Float>();
let r = Float::sin(theta);
Dir3::new(Float::sin(phi) * r, Float::cos(theta), Float::cos(phi) * r)
}
pub fn sample_cosine_hemisphere<R: Rng>(rng: &mut R) -> Self { pub fn sample_cosine_hemisphere<R: Rng>(rng: &mut R) -> Self {
let mut d = Self::sample_disc(rng); let mut d = Self::sample_disc(rng);
d.y = Float::sqrt(Float::max(0.0, 1.0 - d.x * d.x - d.z * d.z)); d.y = Float::sqrt(Float::max(0.0, 1.0 - d.x * d.x - d.z * d.z));

View file

@ -1,5 +1,5 @@
[package] [package]
name = "ray-tracing-material-validator" name = "ray-tracing-material-visualizer"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"

View file

@ -1,13 +0,0 @@
use ray_tracing_core::color::Color;
use ray_tracing_material::{diffuse::DiffuseMaterial, mirror::Mirror};
use ray_tracing_material_validator::generate_chart;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let m = Mirror::new(Color::new(1.0, 1.0, 0.5));
generate_chart("mirror.png", &m, 2)?;
let m = DiffuseMaterial::new(Color::new(1.0, 1.0, 0.5));
generate_chart("diffuse.png", &m, 100)?;
Ok(())
}

View file

@ -1,51 +1,68 @@
use plotters::{coord::Shift, prelude::*}; use plotters::{
chart::ChartBuilder,
coord::Shift,
prelude::{BitMapBackend, DrawingArea, DrawingBackend, IntoDrawingArea},
style::WHITE,
};
use rand::{rngs::SmallRng, SeedableRng}; use rand::{rngs::SmallRng, SeedableRng};
use ray_tracing_core::{color::Color, prelude::*}; use ray_tracing_core::prelude::*;
use rayon::prelude::*; use ray_tracing_material::{diffuse::DiffuseMaterial, mirror::Mirror};
use rayon::iter::{IntoParallelIterator, ParallelExtend, ParallelIterator};
pub fn generate_chart<M: Material<SmallRng>>( fn main() -> Result<(), Box<dyn std::error::Error>> {
let w_in = Dir3::new(1.0, 1.0, 0.0).normalize();
let color = Color::new(1.0, 1.0, 1.0);
let m = Mirror::new(color);
generate_chart("mirror.png", &m, 2, w_in)?;
let m = DiffuseMaterial::new(color);
generate_chart("diffuse.png", &m, 100, w_in)?;
Ok(())
}
fn generate_chart<M: Material<SmallRng>>(
path: impl AsRef<std::path::Path>, path: impl AsRef<std::path::Path>,
m: &M, m: &M,
samples_per_pixel: usize, samples_per_pixel: usize,
w_in: Dir3,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let inner_size = 400; let inner_size = 400;
let width = (inner_size + 70) * 3 + 34; let width = (inner_size + 70) * 3;
let height = (inner_size + 97) * 2; let height = ((inner_size + 97) * 2 + 32) * 2;
let root = BitMapBackend::new(&path, (width, height)).into_drawing_area(); let root = BitMapBackend::new(&path, (width, height)).into_drawing_area();
root.fill(&WHITE)?; root.fill(&WHITE)?;
let area = root.titled("Sampled", ("sans-serif", 30))?; let executions = inner_size as usize * inner_size as usize * samples_per_pixel;
plot_material_sample(&area, m, samples_per_pixel)?;
let areas = root.split_evenly((2, 1));
let eval_histogram = create_histogram_evaled(m, 400, 400, executions, w_in);
let sample_histogram = create_historgram_sampled(m, 400, 400, executions, w_in);
let max = Float::max(eval_histogram.max(), sample_histogram.max());
dbg!(max, eval_histogram.max(), sample_histogram.max());
let area = areas[0].titled("Evaled", ("sans-serif", 30))?;
plot_material(&area, eval_histogram, max)?;
let area = areas[1].titled("Sampled", ("sans-serif", 30))?;
plot_material(&area, sample_histogram, max)?;
root.present()?; root.present()?;
Ok(()) Ok(())
} }
fn plot_material_sample<DB: DrawingBackend, M: Material<SmallRng>>( fn plot_material<DB: DrawingBackend>(
root: &DrawingArea<DB, Shift>, root: &DrawingArea<DB, Shift>,
m: &M, histogram: Histogram,
samples_per_pixel: usize, max: Float,
) -> Result<(), Box<dyn std::error::Error>> ) -> Result<(), Box<dyn std::error::Error>>
where where
DB::ErrorType: 'static, DB::ErrorType: 'static,
{ {
let (xrange, yrange) = root.get_pixel_range();
let width = (xrange.end - xrange.start) as usize;
let height = (yrange.end - yrange.start) as usize;
let width = width / 3 - 70;
let height = height / 2 - 97;
let histogram = create_historgram(
m,
width,
height,
samples_per_pixel * width * height,
Dir3::new(1.0, 1.0, 0.0).normalize(),
);
let areas = root.split_evenly((2, 3)); let areas = root.split_evenly((2, 3));
for (channel, upper, lower) in (0..3).map(|i| (i, &areas[i], &areas[i + 3])) { for (channel, upper, lower) in (0..3).map(|i| (i, &areas[i], &areas[i + 3])) {
let channel_name = match channel { let channel_name = match channel {
@ -95,9 +112,17 @@ where
let lower_area = lower_chart.plotting_area(); let lower_area = lower_chart.plotting_area();
let map = ViridisRGB; let (xrange, yrange) = upper_area.get_pixel_range();
let width = (xrange.end - xrange.start) as usize;
let height = (yrange.end - yrange.start) as usize;
assert_eq!(width, histogram.width);
assert_eq!(height, histogram.height);
let max = histogram.max(); let (xrange, yrange) = lower_area.get_pixel_range();
let width = (xrange.end - xrange.start) as usize;
let height = (yrange.end - yrange.start) as usize;
assert_eq!(width, histogram.width);
assert_eq!(height, histogram.height);
for (dir, f) in histogram.iter() { for (dir, f) in histogram.iter() {
let f = match channel { let f = match channel {
@ -107,7 +132,7 @@ where
_ => unreachable!(), _ => unreachable!(),
}; };
let color = map.get_color_normalized(f, 0.0, max); let color = plotters::prelude::ViridisRGB::get_color_normalized(f, 0.0, max);
if dir.y() < 0.0 { if dir.y() < 0.0 {
lower_area.draw_pixel((dir.x() as f64, dir.z() as f64), &color)?; lower_area.draw_pixel((dir.x() as f64, dir.z() as f64), &color)?;
} else { } else {
@ -139,10 +164,17 @@ impl Histogram {
} }
fn discretize(&self, p: Dir3) -> usize { fn discretize(&self, p: Dir3) -> usize {
(((p.x() + 1.0) * 0.5 * self.width as f32).floor() as usize) assert!(p.x() >= -1.0);
+ (((p.z() + 1.0) * 0.5 * self.height as f32).floor() as usize) * self.width assert!(p.x() <= 1.0);
assert!(p.y() >= -1.0);
assert!(p.y() <= 1.0);
assert!(p.z() >= -1.0);
assert!(p.z() <= 1.0);
(((p.x() + 1.0) * 0.5 * self.width as f32).floor() as usize).min(self.width - 1)
+ (((p.z() + 1.0) * 0.5 * self.height as f32).floor() as usize).min(self.height - 1)
* self.width
+ if p.y() < 0.0 { + if p.y() < 0.0 {
2 * self.width * self.height self.width * self.height
} else { } else {
0 0
} }
@ -217,7 +249,7 @@ impl ParallelExtend<(Dir3, Color)> for Histogram {
} }
} }
fn create_historgram<M: Material<SmallRng>>( fn create_historgram_sampled<M: Material<SmallRng>>(
m: &M, m: &M,
width: usize, width: usize,
height: usize, height: usize,
@ -237,3 +269,27 @@ fn create_historgram<M: Material<SmallRng>>(
h h
} }
fn create_histogram_evaled<M: Material<SmallRng>>(
m: &M,
width: usize,
height: usize,
executions: usize,
w_in: Dir3,
) -> Histogram {
let mut h = Histogram::new(width, height);
h.par_extend(
(0..executions)
.into_par_iter()
.map_init(SmallRng::from_entropy, |rng, _| {
let w_out = Dir3::sample_uniform_sphere(rng);
let color = m.eval(w_in, w_out, rng) * w_out.y() * 4.0 * FloatConsts::PI;
(w_out, color)
}),
);
h
}

View file

@ -47,7 +47,7 @@ where
} }
if let Some(material) = i.material() { if let Some(material) = i.material() {
alpha *= material.eval(w_in, w_out, rng) * w_out.y(); alpha *= material.eval(w_in, w_out, rng) * w_out.y() * 2.0 * FloatConsts::PI;
} else { } else {
return sum; return sum;
} }

View file

@ -64,7 +64,7 @@ pub fn scene<R: Rng + 'static>() -> ExampleScene<R> {
}, },
BVHMaterial { BVHMaterial {
material: None, material: None,
light: Some(Box::new(AreaLight::new(Color::white() * 30.0))), light: Some(Box::new(AreaLight::new(Color::white() * 18.0))),
}, },
BVHMaterial { BVHMaterial {
material: Some(Box::new(Mirror::new(Color::new(1.0, 1.0, 1.0)))), material: Some(Box::new(Mirror::new(Color::new(1.0, 1.0, 1.0)))),

View file

@ -24,7 +24,7 @@ pub fn scene<R: Rng + Debug + 'static>() -> ExampleScene<R> {
.iter() .iter()
.map(|m| match m.name.as_str() { .map(|m| match m.name.as_str() {
"white" => BVHMaterial::new_material(DiffuseMaterial::new(Color::white())), "white" => BVHMaterial::new_material(DiffuseMaterial::new(Color::white())),
"light" => BVHMaterial::new_light(AreaLight::new(Color::white() * 100.0)), "light" => BVHMaterial::new_light(AreaLight::new(Color::white() * 30.0)),
"blue" => { "blue" => {
BVHMaterial::new_material(DiffuseMaterial::new(Color::new(0.0, 0.0, 1.0))) BVHMaterial::new_material(DiffuseMaterial::new(Color::new(0.0, 0.0, 1.0)))
} }

View file

@ -21,7 +21,7 @@ pub fn scene<R: Rng + Debug + 'static>() -> ExampleScene<R> {
let materials = vec![ let materials = vec![
BVHMaterial::new_material(DiffuseMaterial::new(Color::new(0.2, 0.2, 0.9))), BVHMaterial::new_material(DiffuseMaterial::new(Color::new(0.2, 0.2, 0.9))),
BVHMaterial::new_light(AreaLight::new(Color::white() * 100.0)), BVHMaterial::new_light(AreaLight::new(Color::white() * 30.0)),
]; ];
let mut vertices = obj.vertices; let mut vertices = obj.vertices;