Initial upload
This commit is contained in:
132
source/Algorithm/PathTracing.c
Normal file
132
source/Algorithm/PathTracing.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include "Algorithm/PathTracing.h"
|
||||
#include "Common.h"
|
||||
#include "Material.h"
|
||||
|
||||
static hit_result_t ray_intersect(const triangle_t triangle, const ray_t ray)
|
||||
{
|
||||
hit_result_t result = {0};
|
||||
|
||||
vec3s normal = triangle.normal;
|
||||
float n_dot_r = glms_vec3_dot(normal, ray.direction);
|
||||
if (n_dot_r > 0.0f)
|
||||
{
|
||||
normal = glms_vec3_scale(normal, -1.0f);
|
||||
}
|
||||
|
||||
// triangle is parallel to the ray
|
||||
if (fabsf(n_dot_r) < FLT_EPSILON)
|
||||
{
|
||||
result.hit = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get distance from ray origin to triangle plane
|
||||
float distance = (glms_vec3_dot(normal, triangle.point1) - glms_vec3_dot(normal, ray.origin)) / glms_vec3_dot(normal, ray.direction);
|
||||
|
||||
if (distance < FLT_EPSILON)
|
||||
{
|
||||
result.hit = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
vec3s intersection_point = glms_vec3_add(ray.origin, glms_vec3_scale(ray.direction, distance));
|
||||
|
||||
// Check if the intersection point is inside the triangle using barycentric coordinates
|
||||
vec3s edge1 = glms_vec3_sub(triangle.point2, triangle.point1);
|
||||
vec3s edge2 = glms_vec3_sub(triangle.point3, triangle.point2);
|
||||
vec3s edge3 = glms_vec3_sub(triangle.point1, triangle.point3);
|
||||
vec3s vp = glms_vec3_sub(intersection_point, triangle.point1);
|
||||
vec3s vp2 = glms_vec3_sub(intersection_point, triangle.point2);
|
||||
vec3s vp3 = glms_vec3_sub(intersection_point, triangle.point3);
|
||||
|
||||
vec3s c1 = glms_vec3_cross(edge1, vp);
|
||||
vec3s c2 = glms_vec3_cross(edge2, vp2);
|
||||
vec3s c3 = glms_vec3_cross(edge3, vp3);
|
||||
|
||||
if (glms_vec3_dot(triangle.normal, c1) < 0.0f
|
||||
|| glms_vec3_dot(triangle.normal, c2) < 0.0f
|
||||
|| glms_vec3_dot(triangle.normal, c3) < 0.0f)
|
||||
{
|
||||
result.hit = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.hit = true;
|
||||
result.point = intersection_point;
|
||||
result.normal = normal;
|
||||
result.distance = distance;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Implement faster methods like BVH, KD-Tree or uniform grid acceleration
|
||||
vec3s path_trace(const triangle_collection_t* triangles, const material_collection_t* materials, ray_t ray, int max_depth)
|
||||
{
|
||||
vec3s accumulated_color = glms_vec3_zero();
|
||||
vec3s throughput = glms_vec3_one();
|
||||
|
||||
int depth = 0;
|
||||
while (depth < max_depth)
|
||||
{
|
||||
uint8_t material_id = 255;
|
||||
hit_result_t closest_hit = {0};
|
||||
closest_hit.distance = 1145141919.810f;
|
||||
|
||||
for (uint64_t i = 0; i < triangles->count; i++)
|
||||
{
|
||||
hit_result_t hit_result = ray_intersect(triangles->buffer[i], ray);
|
||||
if (hit_result.hit && hit_result.distance < closest_hit.distance)
|
||||
{
|
||||
closest_hit = hit_result;
|
||||
material_id = triangles->buffer[i].material_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!closest_hit.hit)
|
||||
{
|
||||
// accumulated_color = glms_vec3_add(accumulated_color, throughput); // TODO: Skybox
|
||||
break;
|
||||
}
|
||||
|
||||
material_t* hit_material = &materials->buffer[material_id];
|
||||
vec3s emission = hit_material->emission;
|
||||
accumulated_color = glms_vec3_add(accumulated_color, glms_vec3_mul(throughput, emission));
|
||||
|
||||
float pdf;
|
||||
vec3s wo = glms_vec3_negate(ray.direction); // We need to negate the direction of the incoming ray
|
||||
vec3s wi = sample_material_bsdf(hit_material, closest_hit.normal, wo, &pdf);
|
||||
//vec3s wi = random_cosine_direction(closest_hit.normal);
|
||||
//float cos_theta_s = fmaxf(0.0f, glms_vec3_dot(wi, closest_hit.normal));
|
||||
//float pdf = cos_theta_s / (float)M_PI;
|
||||
if (pdf < 0.0f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
shading_context_t shading_context = {
|
||||
.normal = closest_hit.normal,
|
||||
.wi = wi,
|
||||
.wo = wo
|
||||
};
|
||||
vec3s bsdf = evaluate_material_bsdf(hit_material, &shading_context);
|
||||
float cos_theta = fmaxf(0.0f, glms_vec3_dot(wi, closest_hit.normal));
|
||||
throughput = glms_vec3_mul(throughput, glms_vec3_scale(bsdf, cos_theta / pdf));
|
||||
|
||||
// We do Russian roulette to decide whether to continue tracing or terminate the path
|
||||
if (depth > 2)
|
||||
{
|
||||
float q = fminf(glms_vec3_max(throughput), 0.95f);
|
||||
if (random_float() > q)
|
||||
{
|
||||
break; // Terminate the path
|
||||
}
|
||||
}
|
||||
|
||||
ray.origin = glms_vec3_add(closest_hit.point, glms_vec3_scale(closest_hit.normal, FLT_EPSILON));
|
||||
ray.direction = wi;
|
||||
|
||||
depth++;
|
||||
}
|
||||
|
||||
return accumulated_color;
|
||||
}
|
||||
Reference in New Issue
Block a user