diffuse path tracing
This commit is contained in:
parent
8cb5476588
commit
44514117cd
10 changed files with 62 additions and 46 deletions
|
|
@ -12,3 +12,4 @@ cgmath = "0.18.0"
|
||||||
rayon = "1.8.0"
|
rayon = "1.8.0"
|
||||||
image = "0.24.7"
|
image = "0.24.7"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
indicatif = { version = "0.17.7", features = ["rayon"] }
|
||||||
BIN
first_really_good_image.png
Normal file
BIN
first_really_good_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 714 KiB |
BIN
result_image.png
BIN
result_image.png
Binary file not shown.
|
Before Width: | Height: | Size: 469 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -48,8 +48,7 @@ pub fn normalize_colors_global(radiosity_buffer: &mut Vec<Vec<Vector4<f32>>>) ->
|
||||||
});
|
});
|
||||||
|
|
||||||
//calculate difference between min and max pixel radiosity
|
//calculate difference between min and max pixel radiosity
|
||||||
//TODO: drop upper 20 percent of radiosity to illiminate outliers
|
let range = maximum_radiosity - minimum_radiosity;
|
||||||
let range = (maximum_radiosity * 0.8) - minimum_radiosity;
|
|
||||||
//normalize to range
|
//normalize to range
|
||||||
for column in &mut *radiosity_buffer {
|
for column in &mut *radiosity_buffer {
|
||||||
for radiosity_value in column {
|
for radiosity_value in column {
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ fn main() {
|
||||||
&args.gltf_file_path)
|
&args.gltf_file_path)
|
||||||
.expect(&*format!("Failed to load glTF file {}", &args.gltf_file_path));
|
.expect(&*format!("Failed to load glTF file {}", &args.gltf_file_path));
|
||||||
|
|
||||||
|
println!("Path tracing image. Columns finished:");
|
||||||
let mut radiosity_buffer: Vec<Vec<Vector4<f32>>> = match render(scenes, &args).lock() {
|
let mut radiosity_buffer: Vec<Vec<Vector4<f32>>> = match render(scenes, &args).lock() {
|
||||||
Ok(buffer) => {buffer.to_vec()}
|
Ok(buffer) => {buffer.to_vec()}
|
||||||
Err(_) => {panic!("Unable to lock radiosity buffer!")}
|
Err(_) => {panic!("Unable to lock radiosity buffer!")}
|
||||||
|
|
@ -64,6 +65,6 @@ fn main() {
|
||||||
let output_image =
|
let output_image =
|
||||||
store_colors_to_image(as_colors);
|
store_colors_to_image(as_colors);
|
||||||
|
|
||||||
output_image.save("result_image.png").expect("Unable to save image!");
|
output_image.save("../output_image.png").expect("Unable to save image!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
|
use indicatif::ProgressIterator;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{Add, Mul};
|
||||||
use std::sync::{Arc, LockResult, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use cgmath::{Angle, ElementWise, InnerSpace, Matrix4, Vector2, Vector3, Vector4};
|
use cgmath::{Angle, ElementWise, InnerSpace, Matrix4, Vector2, Vector3, Vector4};
|
||||||
|
use cgmath::num_traits::abs;
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use easy_gltf::model::{Mode};
|
use easy_gltf::model::{Mode};
|
||||||
use easy_gltf::{Camera, Projection, Scene};
|
use easy_gltf::{Camera, Projection, Scene};
|
||||||
use rayon::prelude::IntoParallelRefIterator;
|
use indicatif::ParallelProgressIterator;
|
||||||
use crate::Args;
|
use crate::Args;
|
||||||
use crate::geometry::{Intersectable};
|
use crate::geometry::{Intersectable};
|
||||||
use crate::ray::{construct_primary_rays, Ray};
|
use crate::ray::{construct_primary_rays, Ray};
|
||||||
|
|
@ -51,7 +53,9 @@ pub fn render(scenes: &Vec<Scene>,
|
||||||
});
|
});
|
||||||
|
|
||||||
//iterate over all pixels in the image
|
//iterate over all pixels in the image
|
||||||
(0..cl_args.width).into_par_iter().for_each(|px| {
|
(0..cl_args.width).into_par_iter()
|
||||||
|
.progress_count(cl_args.width as u64)
|
||||||
|
.for_each(|px| {
|
||||||
(0..cl_args.height).into_par_iter().for_each(|py| {
|
(0..cl_args.height).into_par_iter().for_each(|py| {
|
||||||
//construct all rays
|
//construct all rays
|
||||||
let rays: Vec<Ray> = construct_primary_rays(
|
let rays: Vec<Ray> = construct_primary_rays(
|
||||||
|
|
@ -121,6 +125,7 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth_left: usize) -> Vector4<f3
|
||||||
isec,
|
isec,
|
||||||
model.material(),
|
model.material(),
|
||||||
triangle.clone(),
|
triangle.clone(),
|
||||||
|
ray,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -161,27 +166,31 @@ fn accumulate_colors(intersection_data: &IntersectionData,
|
||||||
let intersected_triangle = intersection_data.intersected_triangle();
|
let intersected_triangle = intersection_data.intersected_triangle();
|
||||||
let tangent = (intersected_triangle[0].position -
|
let tangent = (intersected_triangle[0].position -
|
||||||
intersected_triangle[1].position).normalize();
|
intersected_triangle[1].position).normalize();
|
||||||
let face_normal: Vector3<f32> = tangent
|
let mut face_normal: Vector3<f32> = tangent
|
||||||
.cross(intersected_triangle[0].position -
|
.cross(intersected_triangle[0].position -
|
||||||
intersected_triangle[2].position).normalize();
|
intersected_triangle[2].position).normalize();
|
||||||
let bitangent = tangent.cross(face_normal);
|
//flip normal if face is hit from behind
|
||||||
|
if face_normal.dot(-intersection_data.ray().direction) < 0.0 {
|
||||||
|
face_normal *= -1.0;
|
||||||
|
}
|
||||||
|
let bitangent = tangent.cross(face_normal).normalize();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
generate random direction on hemisphere
|
generate random direction on hemisphere
|
||||||
*/
|
*/
|
||||||
let phi = rand::random::<f32>() * 2.0 * PI;
|
let phi = rand::random::<f32>() * 2.0 * PI;
|
||||||
//allow arbitrary angles
|
//allow arbitrary angles
|
||||||
let theta = rand::random::<f32>() * 2.0 * PI;
|
let radius = rand::random::<f32>();
|
||||||
|
let sqrt_radius = f32::sqrt(rand::random::<f32>());
|
||||||
|
|
||||||
let sin_theta = f32::sin(theta);
|
let direction = (tangent * f32::cos(phi) * sqrt_radius +
|
||||||
let direction = tangent * f32::cos(phi) * sin_theta +
|
bitangent * f32::sin(phi) * sqrt_radius +
|
||||||
bitangent * f32::sin(phi) * sin_theta +
|
face_normal * f32::sqrt(1.0 - radius)).normalize();
|
||||||
face_normal * f32::cos(theta);
|
|
||||||
|
|
||||||
let secondary_ray = Ray {
|
let secondary_ray = Ray {
|
||||||
//prevent self-intersection
|
//prevent self-intersection
|
||||||
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
|
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
|
||||||
direction: direction.normalize(),
|
direction,
|
||||||
};
|
};
|
||||||
|
|
||||||
//path trace recursively
|
//path trace recursively
|
||||||
|
|
@ -193,10 +202,8 @@ fn accumulate_colors(intersection_data: &IntersectionData,
|
||||||
|
|
||||||
let cos_weighting = direction.dot(face_normal);
|
let cos_weighting = direction.dot(face_normal);
|
||||||
|
|
||||||
//make ray contribution decay exponentially
|
|
||||||
let brdf = intersection_data.material()
|
let brdf = intersection_data.material()
|
||||||
.get_base_color_alpha(Vector2::new(0.0, 0.0))
|
.get_base_color_alpha(Vector2::new(0.0, 0.0));
|
||||||
* (1.0 - f32::powf(6.0, -0.5 * recursion_depth_left as f32));
|
|
||||||
|
|
||||||
//reflected component
|
//reflected component
|
||||||
pixel_radiosity += brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI;
|
pixel_radiosity += brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI;
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,26 @@ use std::sync::Arc;
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
use easy_gltf::{Material};
|
use easy_gltf::{Material};
|
||||||
use easy_gltf::model::Triangle;
|
use easy_gltf::model::Triangle;
|
||||||
|
use crate::ray::Ray;
|
||||||
|
|
||||||
pub(crate) struct IntersectionData {
|
pub(crate) struct IntersectionData<'a> {
|
||||||
intersection_point: Vector3<f32>,
|
intersection_point: Vector3<f32>,
|
||||||
material: Arc<Material>,
|
material: Arc<Material>,
|
||||||
intersected_triangle: Triangle,
|
intersected_triangle: Triangle,
|
||||||
|
ray: &'a Ray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntersectionData {
|
impl IntersectionData<'_>{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
intersection_point: Vector3<f32>,
|
intersection_point: Vector3<f32>,
|
||||||
material: Arc<Material>,
|
material: Arc<Material>,
|
||||||
intersected_triangle: Triangle) -> IntersectionData {
|
intersected_triangle: Triangle,
|
||||||
|
ray: &Ray) -> IntersectionData {
|
||||||
IntersectionData {
|
IntersectionData {
|
||||||
intersection_point,
|
intersection_point,
|
||||||
material,
|
material,
|
||||||
intersected_triangle,
|
intersected_triangle,
|
||||||
|
ray,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,4 +36,8 @@ impl IntersectionData {
|
||||||
pub fn intersected_triangle(&self) -> Triangle {
|
pub fn intersected_triangle(&self) -> Triangle {
|
||||||
self.intersected_triangle
|
self.intersected_triangle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ray(&self) -> &Ray {
|
||||||
|
self.ray
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue