basic path tracing
This commit is contained in:
parent
7f9af4ceaa
commit
507ee2011c
8 changed files with 43 additions and 16 deletions
BIN
result_image.png
BIN
result_image.png
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 686 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
||||||
use std::ops::{Mul, MulAssign};
|
use std::ops::{MulAssign};
|
||||||
use cgmath::{ElementWise, Vector4};
|
use cgmath::{ElementWise, Vector4};
|
||||||
use image::{DynamicImage, GenericImage, Rgba};
|
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;
|
let range = maximum_colors - minimum_colors;
|
||||||
//normalize to range
|
//normalize to range
|
||||||
for column in &mut *radiosity_buffer {
|
for column in &mut *radiosity_buffer {
|
||||||
for mut radiosity_value in column {
|
for radiosity_value in column {
|
||||||
//normalize to range
|
//normalize to range
|
||||||
radiosity_value.div_assign_element_wise(range);
|
radiosity_value.div_assign_element_wise(range);
|
||||||
//map to [0.0..255]
|
//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());
|
let mut color_buffer: Vec<Vec<Rgba<u8>>> = Vec::with_capacity(radiosity_buffer.len());
|
||||||
radiosity_buffer.iter().enumerate().for_each(|(x, col)| {
|
radiosity_buffer.iter().enumerate().for_each(|(x, col)| {
|
||||||
color_buffer.push(Vec::with_capacity(radiosity_buffer[0].len()));
|
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
|
//ceil and cast individual colors
|
||||||
let casted = color_value.map(|comp| {
|
let casted = color_value.map(|comp| {
|
||||||
f32::ceil(comp) as u8
|
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]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,9 @@ mod scene_data;
|
||||||
mod colors;
|
mod colors;
|
||||||
|
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::sync::{Arc, LockResult, Mutex};
|
|
||||||
use cgmath::Vector4;
|
use cgmath::Vector4;
|
||||||
use clap::{Parser};
|
use clap::{Parser};
|
||||||
use easy_gltf::Scene;
|
use easy_gltf::Scene;
|
||||||
use image::{DynamicImage};
|
|
||||||
use crate::colors::{map_radmap_to_colors, normalize_colors_global, store_colors_to_image};
|
use crate::colors::{map_radmap_to_colors, normalize_colors_global, store_colors_to_image};
|
||||||
use crate::renderer::render;
|
use crate::renderer::render;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
|
use std::f32::consts::PI;
|
||||||
use std::ops::{Add, Mul};
|
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 cgmath::{Angle, ElementWise, InnerSpace, Matrix4, Vector2, Vector3, Vector4};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use easy_gltf::model::{Mode};
|
use easy_gltf::model::{Mode};
|
||||||
use easy_gltf::{Camera, Material, Projection, Scene};
|
use easy_gltf::{Camera, Projection, Scene};
|
||||||
use crate::Args;
|
use crate::Args;
|
||||||
use crate::geometry::{Intersectable};
|
use crate::geometry::{Intersectable};
|
||||||
use crate::ray::{construct_primary_rays, Ray};
|
use crate::ray::{construct_primary_rays, Ray};
|
||||||
use crate::scene_data::IntersectionData;
|
use crate::scene_data::IntersectionData;
|
||||||
|
|
||||||
const RAY_EPSILON: f32 = 0.0007;
|
const RAY_EPSILON: f32 = 0.0007;
|
||||||
|
const EMISSION_MULTIPLIER: f32 = 10.0;
|
||||||
|
|
||||||
pub fn render(scenes: &Vec<Scene>,
|
pub fn render(scenes: &Vec<Scene>,
|
||||||
cl_args: &Args) -> Arc<Mutex<Vec<Vec<Vector4<f32>>>>> {
|
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
|
// 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 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)));
|
Arc::new(Mutex::new(Vec::with_capacity(cl_args.width)));
|
||||||
|
|
||||||
//prepare the radiosity buffer
|
//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);
|
let mut empty_vector = Vec::with_capacity(cl_args.height);
|
||||||
for _ in 0..cl_args.height {
|
for _ in 0..cl_args.height {
|
||||||
empty_vector.push(Vector4::new(0.0, 0.0, 0.0, 0.0));
|
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))
|
.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
|
//get the intersected triangle and calculate the face normals
|
||||||
let intersected_triangle = intersection_data.intersected_triangle();
|
let intersected_triangle = intersection_data.intersected_triangle();
|
||||||
let face_normal: Vector3<f32> = (intersected_triangle[0].position - intersected_triangle[1].position)
|
let tangent = (intersected_triangle[0].position -
|
||||||
.cross(intersected_triangle[0].position - intersected_triangle[2].position).normalize();
|
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 {
|
let secondary_ray = Ray {
|
||||||
//prevent self-intersection
|
//prevent self-intersection
|
||||||
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
|
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,
|
&secondary_ray,
|
||||||
global_scene,
|
global_scene,
|
||||||
recursion_depth_left - 1);
|
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
|
//reflected component
|
||||||
pixel_radiosity += incoming_radiosity * 0.2;
|
pixel_radiosity += (brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI) ;
|
||||||
|
|
||||||
pixel_radiosity
|
pixel_radiosity
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
use easy_gltf::{Material, Scene};
|
use easy_gltf::{Material};
|
||||||
use easy_gltf::model::Triangle;
|
use easy_gltf::model::Triangle;
|
||||||
|
|
||||||
pub(crate) struct IntersectionData {
|
pub(crate) struct IntersectionData {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue