reflection directly along normal
This commit is contained in:
parent
1e752d60bf
commit
7f9af4ceaa
7 changed files with 68 additions and 26 deletions
BIN
result_image.png
BIN
result_image.png
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue