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
let range = maximum_radiosity - minimum_radiosity;
//normalize to range
for column in &mut *radiosity_buffer {
for radiosity_value in column {
//Gamma correct
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
radiosity_value.div_assign_element_wise(range);
//map to [0.0..255]

View file

@ -38,7 +38,7 @@ pub struct Args {
debug: bool,
///path tracing recursion depth
#[arg(long)]
recurse: usize
recurse: usize,
}
fn main() {
@ -52,8 +52,8 @@ fn main() {
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!")}
Ok(buffer) => { buffer.to_vec() }
Err(_) => { panic!("Unable to lock radiosity buffer!") }
};
//normalize radiosity values globally
@ -66,6 +66,8 @@ fn main() {
let output_image =
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
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 -
triangle[1].position).normalize();
tangent.cross(triangle[0].position -
triangle[2].position).normalize()
let mut normal = tangent.cross(triangle[0].position -
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 crate::Args;
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::scene_data::IntersectionData;
const RAY_EPSILON: f32 = 0.0007;
const RAY_DECAY: f32 = 0.1;
pub fn render(scenes: &Vec<Scene>,
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 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)
);
raytrace(&ray,
render_scene,
cl_args.recurse,
));
});
//store radiosity into the buffer
@ -87,12 +89,18 @@ pub fn render(scenes: &Vec<Scene>,
radiosity_buffer
}
fn raytrace(ray: &Ray, scene: &Scene, recursion_depth_left: usize) -> Vector4<f32> {
/// raytrace recursively
/// 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);
//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 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
fn accumulate_colors(intersection_data: &IntersectionData,
global_scene: &Scene,
recursion_depth_left: usize) -> Vector4<f32> {
recursion_depth_left: usize,
) -> Vector4<f32> {
let mut pixel_radiosity: Vector4<f32>
= 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))
);
//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
let intersected_triangle = intersection_data.intersected_triangle();
@ -169,8 +182,10 @@ fn accumulate_colors(intersection_data: &IntersectionData,
let decision_factor = rand::random::<f32>();
let mut direction: Vector3<f32>;
let face_normal =
face_normal_for_triangle(&intersection_data.intersected_triangle());
let face_normal = face_normal_for_triangle(
&intersection_data.intersected_triangle(),
intersection_data.ray().direction,
);
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(),
);
} else {
//mirror vector (specular sampling)
direction = intersection_data.ray().direction -
2.0 * (intersection_data.ray().direction.dot(face_normal)) * face_normal;
direction = mirror_ray(intersection_data.ray().direction, face_normal);
}
direction = direction.normalize();
@ -196,10 +209,12 @@ fn accumulate_colors(intersection_data: &IntersectionData,
};
//path trace recursively
let incoming_radiosity: Vector4<f32> = raytrace(
let incoming_radiosity: Vector4<f32> =
raytrace(
&secondary_ray,
global_scene,
recursion_depth_left - 1);
recursion_depth_left - 1,
);
//weigh by cosine term depending on view angel
let cos_weighting = direction.dot(
@ -212,12 +227,18 @@ fn accumulate_colors(intersection_data: &IntersectionData,
brdf = intersection_data.material()
//TODO: texture sampling!
.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 {
//specular sampling
pixel_radiosity += incoming_radiosity * cos_weighting * 2.0 * PI +
intersection_data.material()
//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