basic path tracing

This commit is contained in:
CDaut 2023-11-27 22:26:16 +01:00
parent 7f9af4ceaa
commit 507ee2011c
8 changed files with 43 additions and 16 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 686 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,4 @@
use std::ops::{Mul, MulAssign};
use std::ops::{MulAssign};
use cgmath::{ElementWise, Vector4};
use image::{DynamicImage, GenericImage, Rgba};
@ -61,7 +61,7 @@ pub fn normalize_colors_global(radiosity_buffer: &mut Vec<Vec<Vector4<f32>>>) ->
let range = maximum_colors - minimum_colors;
//normalize to range
for column in &mut *radiosity_buffer {
for mut radiosity_value in column {
for radiosity_value in column {
//normalize to range
radiosity_value.div_assign_element_wise(range);
//map to [0.0..255]
@ -77,12 +77,13 @@ pub fn map_radmap_to_colors(radiosity_buffer: &Vec<Vec<Vector4<f32>>>) -> Vec<Ve
let mut color_buffer: Vec<Vec<Rgba<u8>>> = Vec::with_capacity(radiosity_buffer.len());
radiosity_buffer.iter().enumerate().for_each(|(x, col)| {
color_buffer.push(Vec::with_capacity(radiosity_buffer[0].len()));
col.iter().enumerate().for_each(|(y, color_value)| {
col.iter().enumerate().for_each(|(_y, color_value)| {
//ceil and cast individual colors
let casted = color_value.map(|comp| {
f32::ceil(comp) as u8
});
color_buffer[x].push(Rgba::from([casted.x, casted.y, casted.z, casted.w]));
//TODO: no alpha rendering
color_buffer[x].push(Rgba::from([casted.x, casted.y, casted.z, 255]));
});
});

View file

@ -7,11 +7,9 @@ mod scene_data;
mod colors;
use std::string::String;
use std::sync::{Arc, LockResult, Mutex};
use cgmath::Vector4;
use clap::{Parser};
use easy_gltf::Scene;
use image::{DynamicImage};
use crate::colors::{map_radmap_to_colors, normalize_colors_global, store_colors_to_image};
use crate::renderer::render;

View file

@ -1,15 +1,17 @@
use std::f32::consts::PI;
use std::ops::{Add, Mul};
use std::sync::{Arc, LockResult, Mutex};
use std::sync::{Arc, Mutex};
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};
use easy_gltf::{Camera, Projection, Scene};
use crate::Args;
use crate::geometry::{Intersectable};
use crate::ray::{construct_primary_rays, Ray};
use crate::scene_data::IntersectionData;
const RAY_EPSILON: f32 = 0.0007;
const EMISSION_MULTIPLIER: f32 = 10.0;
pub fn render(scenes: &Vec<Scene>,
cl_args: &Args) -> Arc<Mutex<Vec<Vec<Vector4<f32>>>>> {
@ -36,11 +38,11 @@ pub fn render(scenes: &Vec<Scene>,
// the distance from the camera origin to the view plane
let z: f32 = cl_args.height as f32 / (2.0 * fovy.mul(0.5).tan());
let mut radiosity_buffer: Arc<Mutex<Vec<Vec<Vector4<f32>>>>> =
let radiosity_buffer: Arc<Mutex<Vec<Vec<Vector4<f32>>>>> =
Arc::new(Mutex::new(Vec::with_capacity(cl_args.width)));
//prepare the radiosity buffer
(0..cl_args.width).into_iter().for_each(|px| {
(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));
@ -154,24 +156,50 @@ fn accumulate_colors(intersection_data: &IntersectionData,
.get_base_color_alpha(Vector2::new(0.0, 0.0))
);
//TODO: hack, because light sources are always too dim
pixel_radiosity *= EMISSION_MULTIPLIER;
//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();
let tangent = (intersected_triangle[0].position -
intersected_triangle[1].position).normalize();
let face_normal: Vector3<f32> = tangent
.cross(intersected_triangle[0].position -
intersected_triangle[2].position).normalize();
let bitangent = tangent.cross(face_normal);
/**
generate random direction on hemisphere
**/
let phi = rand::random::<f32>() * 2.0 * PI;
//allow arbitrary angles
let theta = rand::random::<f32>() * 2.0 * PI;
let sin_theta = f32::sin(theta);
let direction = tangent * f32::cos(phi) * sin_theta +
bitangent * f32::sin(phi) * sin_theta +
face_normal * f32::cos(theta);
let secondary_ray = Ray {
//prevent self-intersection
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
direction: face_normal,
direction: direction.normalize(),
};
let incoming_radiosity = raytrace(
//path trace recursively
let incoming_radiosity: Vector4<f32> = raytrace(
&secondary_ray,
global_scene,
recursion_depth_left - 1);
let cos_weighting = direction.dot(face_normal);
let brdf = 0.5 * intersection_data.material().get_base_color_alpha(
Vector2::new(0.0,0.0)
);
//reflected component
pixel_radiosity += incoming_radiosity * 0.2;
pixel_radiosity += (brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI) ;
pixel_radiosity
}

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use cgmath::Vector3;
use easy_gltf::{Material, Scene};
use easy_gltf::{Material};
use easy_gltf::model::Triangle;
pub(crate) struct IntersectionData {