diffuse path tracing
This commit is contained in:
parent
8cb5476588
commit
44514117cd
10 changed files with 62 additions and 46 deletions
|
|
@ -11,4 +11,5 @@ clap = { version = "4.4.8", features = ["derive"] }
|
|||
cgmath = "0.18.0"
|
||||
rayon = "1.8.0"
|
||||
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
|
||||
//TODO: drop upper 20 percent of radiosity to illiminate outliers
|
||||
let range = (maximum_radiosity * 0.8) - minimum_radiosity;
|
||||
let range = maximum_radiosity - minimum_radiosity;
|
||||
//normalize to range
|
||||
for column in &mut *radiosity_buffer {
|
||||
for radiosity_value in column {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ fn main() {
|
|||
&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() {
|
||||
Ok(buffer) => {buffer.to_vec()}
|
||||
Err(_) => {panic!("Unable to lock radiosity buffer!")}
|
||||
|
|
@ -64,6 +65,6 @@ fn main() {
|
|||
let output_image =
|
||||
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::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::num_traits::abs;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use easy_gltf::model::{Mode};
|
||||
use easy_gltf::{Camera, Projection, Scene};
|
||||
use rayon::prelude::IntoParallelRefIterator;
|
||||
use indicatif::ParallelProgressIterator;
|
||||
use crate::Args;
|
||||
use crate::geometry::{Intersectable};
|
||||
use crate::ray::{construct_primary_rays, Ray};
|
||||
|
|
@ -51,36 +53,38 @@ pub fn render(scenes: &Vec<Scene>,
|
|||
});
|
||||
|
||||
//iterate over all pixels in the image
|
||||
(0..cl_args.width).into_par_iter().for_each(|px| {
|
||||
(0..cl_args.height).into_par_iter().for_each(|py| {
|
||||
//construct all rays
|
||||
let rays: Vec<Ray> = construct_primary_rays(
|
||||
(cl_args.width, cl_args.height),
|
||||
(px, py),
|
||||
&transform_matrix,
|
||||
z,
|
||||
cl_args.multiplier,
|
||||
);
|
||||
|
||||
//let the initial pixel color be black and opaque
|
||||
let mut pixel_radiosity: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
//cast each ray and get the output luminosity and sum them up
|
||||
rays.iter().for_each(|ray| {
|
||||
pixel_radiosity = pixel_radiosity.add(
|
||||
raytrace(&ray, render_scene, cl_args.recurse)
|
||||
(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| {
|
||||
//construct all rays
|
||||
let rays: Vec<Ray> = construct_primary_rays(
|
||||
(cl_args.width, cl_args.height),
|
||||
(px, py),
|
||||
&transform_matrix,
|
||||
z,
|
||||
cl_args.multiplier,
|
||||
);
|
||||
});
|
||||
|
||||
//store radiosity into the buffer
|
||||
match radiosity_buffer.clone().lock() {
|
||||
Ok(mut buffer) => {
|
||||
buffer[px][py] = pixel_radiosity;
|
||||
//let the initial pixel color be black and opaque
|
||||
let mut pixel_radiosity: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
//cast each ray and get the output luminosity and sum them up
|
||||
rays.iter().for_each(|ray| {
|
||||
pixel_radiosity = pixel_radiosity.add(
|
||||
raytrace(&ray, render_scene, cl_args.recurse)
|
||||
);
|
||||
});
|
||||
|
||||
//store radiosity into the buffer
|
||||
match radiosity_buffer.clone().lock() {
|
||||
Ok(mut buffer) => {
|
||||
buffer[px][py] = pixel_radiosity;
|
||||
}
|
||||
Err(_) => { panic!("Unable to lock pixel buffer!") }
|
||||
}
|
||||
Err(_) => { panic!("Unable to lock pixel buffer!") }
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
radiosity_buffer
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +125,7 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth_left: usize) -> Vector4<f3
|
|||
isec,
|
||||
model.material(),
|
||||
triangle.clone(),
|
||||
ray,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -161,27 +166,31 @@ fn accumulate_colors(intersection_data: &IntersectionData,
|
|||
let intersected_triangle = intersection_data.intersected_triangle();
|
||||
let tangent = (intersected_triangle[0].position -
|
||||
intersected_triangle[1].position).normalize();
|
||||
let face_normal: Vector3<f32> = tangent
|
||||
let mut face_normal: Vector3<f32> = tangent
|
||||
.cross(intersected_triangle[0].position -
|
||||
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
|
||||
*/
|
||||
let phi = rand::random::<f32>() * 2.0 * PI;
|
||||
//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) * sin_theta +
|
||||
bitangent * f32::sin(phi) * sin_theta +
|
||||
face_normal * f32::cos(theta);
|
||||
let direction = (tangent * f32::cos(phi) * sqrt_radius +
|
||||
bitangent * f32::sin(phi) * sqrt_radius +
|
||||
face_normal * f32::sqrt(1.0 - radius)).normalize();
|
||||
|
||||
let secondary_ray = Ray {
|
||||
//prevent self-intersection
|
||||
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
|
||||
direction: direction.normalize(),
|
||||
direction,
|
||||
};
|
||||
|
||||
//path trace recursively
|
||||
|
|
@ -193,10 +202,8 @@ fn accumulate_colors(intersection_data: &IntersectionData,
|
|||
|
||||
let cos_weighting = direction.dot(face_normal);
|
||||
|
||||
//make ray contribution decay exponentially
|
||||
let brdf = intersection_data.material()
|
||||
.get_base_color_alpha(Vector2::new(0.0, 0.0))
|
||||
* (1.0 - f32::powf(6.0, -0.5 * recursion_depth_left as f32));
|
||||
.get_base_color_alpha(Vector2::new(0.0, 0.0));
|
||||
|
||||
//reflected component
|
||||
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 easy_gltf::{Material};
|
||||
use easy_gltf::model::Triangle;
|
||||
use crate::ray::Ray;
|
||||
|
||||
pub(crate) struct IntersectionData {
|
||||
pub(crate) struct IntersectionData<'a> {
|
||||
intersection_point: Vector3<f32>,
|
||||
material: Arc<Material>,
|
||||
intersected_triangle: Triangle,
|
||||
ray: &'a Ray,
|
||||
}
|
||||
|
||||
impl IntersectionData {
|
||||
impl IntersectionData<'_>{
|
||||
pub fn new(
|
||||
intersection_point: Vector3<f32>,
|
||||
material: Arc<Material>,
|
||||
intersected_triangle: Triangle) -> IntersectionData {
|
||||
intersected_triangle: Triangle,
|
||||
ray: &Ray) -> IntersectionData {
|
||||
IntersectionData {
|
||||
intersection_point,
|
||||
material,
|
||||
intersected_triangle,
|
||||
ray,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,4 +36,8 @@ impl IntersectionData {
|
|||
pub fn intersected_triangle(&self) -> Triangle {
|
||||
self.intersected_triangle
|
||||
}
|
||||
|
||||
pub fn ray(&self) -> &Ray {
|
||||
self.ray
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue