reflection directly along normal

This commit is contained in:
CDaut 2023-11-27 20:59:25 +01:00
parent 1e752d60bf
commit 7f9af4ceaa
7 changed files with 68 additions and 26 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -37,6 +37,9 @@ pub struct Args {
///start in debug mode (e.g. without parallelization)
#[arg(long)]
debug: bool,
///path tracing recursion depth
#[arg(long)]
recurse: usize
}
fn main() {

View file

@ -1,6 +1,6 @@
use std::ops::{Add, Mul};
use std::sync::{Arc, LockResult, Mutex};
use cgmath::{Angle, ElementWise, Matrix4, Vector2, Vector3, Vector4};
use cgmath::{Angle, ElementWise, InnerSpace, Matrix4, Vector2, Vector3, Vector4};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use easy_gltf::model::{Mode};
use easy_gltf::{Camera, Material, Projection, Scene};
@ -9,6 +9,8 @@ use crate::geometry::{Intersectable};
use crate::ray::{construct_primary_rays, Ray};
use crate::scene_data::IntersectionData;
const RAY_EPSILON: f32 = 0.0007;
pub fn render(scenes: &Vec<Scene>,
cl_args: &Args) -> Arc<Mutex<Vec<Vec<Vector4<f32>>>>> {
let render_scene: &Scene = &scenes[cl_args.scene_index];
@ -38,13 +40,17 @@ pub fn render(scenes: &Vec<Scene>,
Arc::new(Mutex::new(Vec::with_capacity(cl_args.width)));
//prepare the radiosity buffer
(0..cl_args.height).into_iter().for_each(|py| {
radiosity_buffer.lock().unwrap().push(Vec::with_capacity(cl_args.height))
(0..cl_args.width).into_iter().for_each(|px| {
let mut empty_vector = Vec::with_capacity(cl_args.height);
for _ in 0..cl_args.height {
empty_vector.push(Vector4::new(0.0, 0.0, 0.0, 0.0));
}
radiosity_buffer.lock().unwrap().push(empty_vector);
});
//iterate over all pixels in the image
(0..cl_args.width).into_iter().for_each(|px| {
(0..cl_args.height).into_iter().for_each(|py| {
(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),
@ -60,27 +66,28 @@ pub fn render(scenes: &Vec<Scene>,
//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, 4)
raytrace(ray, render_scene, cl_args.recurse)
);
});
//store radiosity into the buffer
match radiosity_buffer.clone().lock() {
Ok(mut buffer) => {
buffer[px].push(pixel_radiosity);
buffer[px][py] = pixel_radiosity;
}
Err(_) => { panic!("Unable to lock pixel buffer!") }
}
});
});
radiosity_buffer
}
fn raytrace(ray: &Ray, scene: &Scene, recursion_depth: u32) -> Vector4<f32> {
let mut pixel_radiosity: Vector4<f32> = Vector4::new(0.0, 0.0, 0.0, 255.0);
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; }
let mut smallest_t: f32 = f32::MAX;
let mut intersection_data: Option<IntersectionData> = None;
@ -100,8 +107,8 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth: u32) -> Vector4<f32> {
//iterate all triangles in a model
triangles.iter().for_each(|triangle| {
match triangle.test_isec(&ray) {
//boilerplate implementation to set pixel to red if any intersection happened
None => {}
//set data if intersection has been detected
Some((t, isec)) => {
// a new closer Point is found
if t < smallest_t {
@ -110,7 +117,9 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth: u32) -> Vector4<f32> {
Option::from(
IntersectionData::new(
isec,
model.material())
model.material(),
triangle.clone(),
)
);
}
}
@ -120,8 +129,9 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth: u32) -> Vector4<f32> {
match intersection_data {
Some(isec_data) => {
pixel_radiosity = accumulate_colors(isec_data.intersection_point(),
isec_data.material());
pixel_radiosity = accumulate_colors(&isec_data,
&scene,
recursion_depth_left);
}
None {} => {}
}
@ -130,19 +140,38 @@ fn raytrace(ray: &Ray, scene: &Scene, recursion_depth: u32) -> Vector4<f32> {
}
/// called iff an intersection is detected to (recursively) accumulate radiosity at intersection
fn accumulate_colors(_intersection_point: Vector3<f32>, isec_material: &Arc<Material>) -> Vector4<f32> {
fn accumulate_colors(intersection_data: &IntersectionData,
global_scene: &Scene,
recursion_depth_left: usize) -> Vector4<f32> {
let mut pixel_radiosity: Vector4<f32>
= Vector4::new(0.0, 0.0, 0.0, 1.0);
//accumulate colors at point
//emmisive Component
//emissive Component
pixel_radiosity +=
isec_material.emissive.factor.extend(1.0)
intersection_data.material().emissive.factor.extend(1.0)
.mul_element_wise(
isec_material.get_base_color_alpha(Vector2::new(0.0, 0.0))
intersection_data.material()
.get_base_color_alpha(Vector2::new(0.0, 0.0))
);
//get the intersected triangle and calculate the face normals
let intersected_triangle = intersection_data.intersected_triangle();
let face_normal: Vector3<f32> = (intersected_triangle[0].position - intersected_triangle[1].position)
.cross(intersected_triangle[0].position - intersected_triangle[2].position).normalize();
//TODO: Path tracing. Scatter ray in one random direction
let secondary_ray = Ray {
//prevent self-intersection
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
direction: face_normal,
};
let incoming_radiosity = raytrace(
&secondary_ray,
global_scene,
recursion_depth_left - 1);
//reflected component
pixel_radiosity += incoming_radiosity * 0.2;
pixel_radiosity
}

View file

@ -1,17 +1,23 @@
use std::sync::Arc;
use cgmath::Vector3;
use easy_gltf::Material;
use easy_gltf::{Material, Scene};
use easy_gltf::model::Triangle;
pub(crate) struct IntersectionData {
intersection_point: Vector3<f32>,
material: Arc<Material>
material: Arc<Material>,
intersected_triangle: Triangle,
}
impl IntersectionData {
pub fn new(intersection_point: Vector3<f32>, material: Arc<Material>) -> IntersectionData{
pub fn new(
intersection_point: Vector3<f32>,
material: Arc<Material>,
intersected_triangle: Triangle) -> IntersectionData {
IntersectionData {
intersection_point,
material,
intersected_triangle,
}
}
@ -22,4 +28,8 @@ impl IntersectionData{
pub fn material(&self) -> &Arc<Material> {
&self.material
}
pub fn intersected_triangle(&self) -> Triangle {
self.intersected_triangle
}
}