Add eval to visualizer and fix pbr error
This commit is contained in:
parent
109a72c19a
commit
3a37a72f56
10 changed files with 105 additions and 55 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)))),
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue