specular reflections appear to be working
This commit is contained in:
parent
1a355f81ca
commit
b2e5d7ed47
11 changed files with 71 additions and 27 deletions
BIN
output_image.png
BIN
output_image.png
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 210 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -25,6 +25,7 @@ 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 {
|
||||
|
|
@ -32,6 +33,7 @@ pub fn normalize_colors_global(radiosity_buffer: &mut Vec<Vec<Vector4<f32>>>) ->
|
|||
radiosity_value.map(|single_channel_radiosity|
|
||||
f32::powf(single_channel_radiosity, 1.0 / GAMMA)
|
||||
);
|
||||
|
||||
//normalize to range
|
||||
radiosity_value.div_assign_element_wise(range);
|
||||
//map to [0.0..255]
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ pub struct Args {
|
|||
debug: bool,
|
||||
///path tracing recursion depth
|
||||
#[arg(long)]
|
||||
recurse: usize
|
||||
recurse: usize,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
@ -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!");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue