specular reflections appear to be working

This commit is contained in:
CDaut 2023-12-01 11:31:40 +01:00
parent 1a355f81ca
commit b2e5d7ed47
11 changed files with 71 additions and 27 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -25,13 +25,15 @@ 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
let range = maximum_radiosity - minimum_radiosity; let range = maximum_radiosity - 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 {
//Gamma correct //Gamma correct
radiosity_value.map(|single_channel_radiosity| radiosity_value.map(|single_channel_radiosity|
f32::powf(single_channel_radiosity, 1.0/GAMMA) f32::powf(single_channel_radiosity, 1.0 / GAMMA)
); );
//normalize to range //normalize to range
radiosity_value.div_assign_element_wise(range); radiosity_value.div_assign_element_wise(range);
//map to [0.0..255] //map to [0.0..255]

View file

@ -38,7 +38,7 @@ pub struct Args {
debug: bool, debug: bool,
///path tracing recursion depth ///path tracing recursion depth
#[arg(long)] #[arg(long)]
recurse: usize recurse: usize,
} }
fn main() { fn main() {
@ -52,8 +52,8 @@ fn main() {
println!("Path tracing image. Columns finished:"); 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!") }
}; };
//normalize radiosity values globally //normalize radiosity values globally
@ -66,6 +66,8 @@ fn main() {
let output_image = let output_image =
store_colors_to_image(as_colors); store_colors_to_image(as_colors);
output_image.save("/home/clemens/repositorys/raytrace-rs/output_image.png").expect("Unable to save image!"); output_image
.save("/home/clemens/repositorys/raytrace-rs/output_image.png")
.expect("Unable to save image!");
} }

View file

@ -29,9 +29,28 @@ pub fn uniform_random_angle_triangle_hemisphere(intersected_triangle: Triangle,
} }
/// Calculate a triangle from the three Vertices /// Calculate a triangle from the three Vertices
pub fn face_normal_for_triangle(triangle: &Triangle) -> Vector3<f32> { pub fn face_normal_for_triangle(triangle: &Triangle, raydir: Vector3<f32>) -> Vector3<f32> {
let tangent = (triangle[0].position - let tangent = (triangle[0].position -
triangle[1].position).normalize(); triangle[1].position).normalize();
tangent.cross(triangle[0].position - let mut normal = tangent.cross(triangle[0].position -
triangle[2].position).normalize() triangle[2].position).normalize();
if normal.dot(-raydir) < 0.0 {
normal *= -1.0;
}
normal
}
/// mirrors the given ray direction vector
/// (assuming to be pointing towards the camera) along the normal
pub fn mirror_ray(ray_direction: Vector3<f32>, normal: Vector3<f32>) -> Vector3<f32> {
let mut new_normal = normal;
if normal.dot(-ray_direction) < 0.0 {
new_normal = normal * -1.0;
}
//mirror vector (specular sampling)
ray_direction -
2.0 * (ray_direction.dot(new_normal)) * new_normal
} }

View file

@ -8,11 +8,12 @@ use easy_gltf::{Camera, Projection, Scene};
use indicatif::ParallelProgressIterator; use indicatif::ParallelProgressIterator;
use crate::Args; use crate::Args;
use crate::geometry::{Intersectable}; use crate::geometry::{Intersectable};
use crate::math_utils::{face_normal_for_triangle, uniform_random_angle_triangle_hemisphere}; use crate::math_utils::{face_normal_for_triangle, mirror_ray, uniform_random_angle_triangle_hemisphere};
use crate::ray::{construct_primary_rays, Ray}; use crate::ray::{construct_primary_rays, Ray};
use crate::scene_data::IntersectionData; use crate::scene_data::IntersectionData;
const RAY_EPSILON: f32 = 0.0007; const RAY_EPSILON: f32 = 0.0007;
const RAY_DECAY: f32 = 0.1;
pub fn render(scenes: &Vec<Scene>, pub fn render(scenes: &Vec<Scene>,
cl_args: &Args) -> Arc<Mutex<Vec<Vec<Vector4<f32>>>>> { cl_args: &Args) -> Arc<Mutex<Vec<Vec<Vector4<f32>>>>> {
@ -67,12 +68,13 @@ pub fn render(scenes: &Vec<Scene>,
//let the initial pixel color be black and opaque //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); 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 //cast each ray and get the output luminosity and sum them up
rays.iter().for_each(|ray| { rays.iter().for_each(|ray| {
pixel_radiosity = pixel_radiosity.add( pixel_radiosity = pixel_radiosity.add(
raytrace(&ray, render_scene, cl_args.recurse) raytrace(&ray,
); render_scene,
cl_args.recurse,
));
}); });
//store radiosity into the buffer //store radiosity into the buffer
@ -87,12 +89,18 @@ pub fn render(scenes: &Vec<Scene>,
radiosity_buffer radiosity_buffer
} }
/// raytrace recursively
fn raytrace(ray: &Ray, scene: &Scene, recursion_depth_left: usize) -> Vector4<f32> { /// returns a Color Vector
fn raytrace(ray: &Ray, scene: &Scene,
recursion_depth_left: usize,
)
-> Vector4<f32> {
let mut pixel_radiosity: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 1.0); let mut pixel_radiosity: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 1.0);
//abort if no recursion steps are left //abort if no recursion steps are left
if recursion_depth_left == 0 { return pixel_radiosity; } if recursion_depth_left == 0 {
return pixel_radiosity;
}
let mut smallest_t: f32 = f32::MAX; let mut smallest_t: f32 = f32::MAX;
let mut intersection_data: Option<IntersectionData> = None; let mut intersection_data: Option<IntersectionData> = None;
@ -148,7 +156,8 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth_left: usize) -> Vector4<f3
/// called iff an intersection is detected to (recursively) accumulate radiosity at intersection /// called iff an intersection is detected to (recursively) accumulate radiosity at intersection
fn accumulate_colors(intersection_data: &IntersectionData, fn accumulate_colors(intersection_data: &IntersectionData,
global_scene: &Scene, global_scene: &Scene,
recursion_depth_left: usize) -> Vector4<f32> { recursion_depth_left: usize,
) -> Vector4<f32> {
let mut pixel_radiosity: Vector4<f32> let mut pixel_radiosity: Vector4<f32>
= Vector4::new(0.0, 0.0, 0.0, 1.0); = Vector4::new(0.0, 0.0, 0.0, 1.0);
@ -162,6 +171,10 @@ fn accumulate_colors(intersection_data: &IntersectionData,
.get_base_color_alpha(Vector2::new(0.0, 0.0)) .get_base_color_alpha(Vector2::new(0.0, 0.0))
); );
//make shorter rays contribute more towards the total radiosity
//TODO: (probably) broken
let ray_decay_factor = f32::powf(recursion_depth_left as f32 + 1.0, RAY_DECAY);
pixel_radiosity *= ray_decay_factor;
//get the intersected triangle and calculate the face normals //get the intersected triangle and calculate the face normals
let intersected_triangle = intersection_data.intersected_triangle(); let intersected_triangle = intersection_data.intersected_triangle();
@ -169,8 +182,10 @@ fn accumulate_colors(intersection_data: &IntersectionData,
let decision_factor = rand::random::<f32>(); let decision_factor = rand::random::<f32>();
let mut direction: Vector3<f32>; let mut direction: Vector3<f32>;
let face_normal = let face_normal = face_normal_for_triangle(
face_normal_for_triangle(&intersection_data.intersected_triangle()); &intersection_data.intersected_triangle(),
intersection_data.ray().direction,
);
let rough_sampling: bool = decision_factor <= intersection_data.material().pbr.roughness_factor; let rough_sampling: bool = decision_factor <= intersection_data.material().pbr.roughness_factor;
@ -182,9 +197,7 @@ fn accumulate_colors(intersection_data: &IntersectionData,
intersection_data.ray(), intersection_data.ray(),
); );
} else { } else {
//mirror vector (specular sampling) direction = mirror_ray(intersection_data.ray().direction, face_normal);
direction = intersection_data.ray().direction -
2.0 * (intersection_data.ray().direction.dot(face_normal)) * face_normal;
} }
direction = direction.normalize(); direction = direction.normalize();
@ -196,10 +209,12 @@ fn accumulate_colors(intersection_data: &IntersectionData,
}; };
//path trace recursively //path trace recursively
let incoming_radiosity: Vector4<f32> = raytrace( let incoming_radiosity: Vector4<f32> =
&secondary_ray, raytrace(
global_scene, &secondary_ray,
recursion_depth_left - 1); global_scene,
recursion_depth_left - 1,
);
//weigh by cosine term depending on view angel //weigh by cosine term depending on view angel
let cos_weighting = direction.dot( let cos_weighting = direction.dot(
@ -212,12 +227,18 @@ fn accumulate_colors(intersection_data: &IntersectionData,
brdf = intersection_data.material() brdf = intersection_data.material()
//TODO: texture sampling! //TODO: texture sampling!
.get_base_color_alpha(Vector2::new(0.0, 0.0)); .get_base_color_alpha(Vector2::new(0.0, 0.0));
pixel_radiosity += brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI;
//weigh incoming radiosity more than own color so object won't look emissive
pixel_radiosity += 1.5 * incoming_radiosity;
pixel_radiosity += 1.2 * brdf.mul_element_wise(incoming_radiosity);
pixel_radiosity *= cos_weighting * 2.0 * PI * ray_decay_factor;
} else { } else {
//specular sampling
pixel_radiosity += incoming_radiosity * cos_weighting * 2.0 * PI + pixel_radiosity += incoming_radiosity * cos_weighting * 2.0 * PI +
intersection_data.material() intersection_data.material()
//TODO: texture sampling! //TODO: texture sampling!
.get_base_color_alpha(Vector2::new(0.0, 0.0)); .get_base_color_alpha(Vector2::new(0.0, 0.0))
* ray_decay_factor;
} }
pixel_radiosity pixel_radiosity