specular metallic materials

This commit is contained in:
CDaut 2023-11-30 22:10:27 +01:00
parent e1c61ef944
commit 1a355f81ca
15 changed files with 533 additions and 27 deletions

View file

@ -5,6 +5,7 @@ mod geometry;
mod ray;
mod scene_data;
mod colors;
mod math_utils;
use std::string::String;
use cgmath::Vector4;

37
src/math_utils.rs Normal file
View file

@ -0,0 +1,37 @@
use std::f32::consts::PI;
use cgmath::{InnerSpace, Vector3};
use easy_gltf::model::Triangle;
use crate::ray::Ray;
/// return a uniform random angle in the hemisphere specified by the triangle
pub fn uniform_random_angle_triangle_hemisphere(intersected_triangle: Triangle, ray: &Ray) -> Vector3<f32> {
let tangent = (intersected_triangle[0].position -
intersected_triangle[1].position).normalize();
let mut face_normal: Vector3<f32> = tangent
.cross(intersected_triangle[0].position -
intersected_triangle[2].position).normalize();
//flip normal if face is hit from behind
if face_normal.dot(-ray.direction) < 0.0 {
face_normal *= -1.0;
}
let bitangent = tangent.cross(face_normal).normalize();
/*
generate random direction on hemisphere
*/
let phi = rand::random::<f32>() * 2.0 * PI;
//allow arbitrary angles
let radius = rand::random::<f32>();
let sqrt_radius = f32::sqrt(rand::random::<f32>());
(tangent * f32::cos(phi) * sqrt_radius +
bitangent * f32::sin(phi) * sqrt_radius +
face_normal * f32::sqrt(1.0 - radius)).normalize()
}
/// Calculate a triangle from the three Vertices
pub fn face_normal_for_triangle(triangle: &Triangle) -> Vector3<f32> {
let tangent = (triangle[0].position -
triangle[1].position).normalize();
tangent.cross(triangle[0].position -
triangle[2].position).normalize()
}

View file

@ -8,6 +8,7 @@ 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::ray::{construct_primary_rays, Ray};
use crate::scene_data::IntersectionData;
@ -150,44 +151,47 @@ fn accumulate_colors(intersection_data: &IntersectionData,
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
//emissive Component
pixel_radiosity +=
intersection_data.material().emissive.factor.extend(1.0)
.mul_element_wise(
intersection_data.material()
//TODO: texture sampling!
.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 tangent = (intersected_triangle[0].position -
intersected_triangle[1].position).normalize();
let mut face_normal: Vector3<f32> = tangent
.cross(intersected_triangle[0].position -
intersected_triangle[2].position).normalize();
//flip normal if face is hit from behind
if face_normal.dot(-intersection_data.ray().direction) < 0.0 {
face_normal *= -1.0;
let decision_factor = rand::random::<f32>();
let mut direction: Vector3<f32>;
let face_normal =
face_normal_for_triangle(&intersection_data.intersected_triangle());
let rough_sampling: bool = decision_factor <= intersection_data.material().pbr.roughness_factor;
//do we trace rough or specular?
if rough_sampling {
//generate random direction (rough sampling)
direction = uniform_random_angle_triangle_hemisphere(
intersected_triangle,
intersection_data.ray(),
);
} else {
//mirror vector (specular sampling)
direction = intersection_data.ray().direction -
2.0 * (intersection_data.ray().direction.dot(face_normal)) * face_normal;
}
let bitangent = tangent.cross(face_normal).normalize();
/*
generate random direction on hemisphere
*/
let phi = rand::random::<f32>() * 2.0 * PI;
//allow arbitrary angles
let radius = rand::random::<f32>();
let sqrt_radius = f32::sqrt(rand::random::<f32>());
let direction = (tangent * f32::cos(phi) * sqrt_radius +
bitangent * f32::sin(phi) * sqrt_radius +
face_normal * f32::sqrt(1.0 - radius)).normalize();
direction = direction.normalize();
let secondary_ray = Ray {
//prevent self-intersection
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
source: intersection_data.intersection_point() + RAY_EPSILON * direction,
direction,
};
@ -197,15 +201,27 @@ fn accumulate_colors(intersection_data: &IntersectionData,
global_scene,
recursion_depth_left - 1);
//weigh by cosine term depending on view angel
let cos_weighting = direction.dot(
face_normal
);
let cos_weighting = direction.dot(face_normal);
let brdf: Vector4<f32>;
let brdf = intersection_data.material()
.get_base_color_alpha(Vector2::new(0.0, 0.0));
//reflected component
pixel_radiosity += brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI;
if rough_sampling {
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;
} else {
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));
}
pixel_radiosity
}