Files
SimpleRayTracing/source/Algorithm/PathTracing.c
Misaki bfc94f0008 Enhance graphics library functionality and structure
Added new function signatures in `assimp-vc143-mt.lib` for improved logging, parsing, and vector operations.
Added new metadata and configuration information in `assimp-vc143-mt.dll` for versioning and licensing compliance.
Added Sobol sequence generation in `Sobol.c` for quasi-random sampling.
Added window message handling in `Window.c` for rendering graphics.
Added ray-triangle intersection tests in `RayIntersection.c` for collision detection.
Added functions for loading mesh data in `Mesh.c` to support 3D model import.
Added functions for managing triangle collections in `Triangle.c` to enhance geometric data handling.
Added light evaluation functions in `LightEvaluation.c` and `SkyLight.c` for realistic rendering.
Added sampling and evaluation functions for simple lit materials in `SimpleLit.c`.
Changed various header files to include copyright and licensing information.
Changed existing functions in multiple files to improve performance and clarity.
Removed unused code in several files to streamline the library.
2025-04-18 01:54:26 +09:00

106 lines
4.2 KiB
C

#include "Algorithm/PathTracing.h"
#include "Algorithm/RayIntersection.h"
#include "Algorithm/BSDF.h"
#include "Algorithm/Sobol.h"
#include "Lighting/LightEvaluation.h"
// TODO: Implement a faster methods like BVH, KD-Tree or uniform grid acceleration
// TODO: Split the diffuse and specular into different Monte Carlo, so we can decide the sample count for each one
vec3s path_trace(const scene_t* scene, const ray_t ray, const uint32_t sample_index, const int max_depth)
{
const triangle_collection_t* triangles = &scene->triangles;
const material_collection_t* materials = &scene->materials;
const light_collection_t* lights = &scene->lights;
vec3s accumulated_color = glms_vec3_zero();
vec3s throughput = glms_vec3_one();
ray_t active_ray = ray;
vec3s prev_normal = glms_vec3_zero();
float pdf_bsdf = 1.0f; // Even though pdf_bsdf should be avaliable after the first bounce. For seafty, we set it to 1.0f for the first iteration.
sobol_state_t sobol_state = {sample_index, 0};
int depth = 0;
while (depth < max_depth)
{
hit_result_t closest_hit = ray_intersect_closest(triangles, active_ray);
if (!closest_hit.hit)
{
vec3s sky_light = evaluate_bsdf_sky(scene, NULL, &sobol_state);
if (depth > 0)
{
// Have to multiply the weight since we evaluate the sky at each bounce
float pdf_nee = pdf_cosine_weighted_hemisphere(prev_normal, active_ray.direction);
float weight = power_heuristic(pdf_bsdf, pdf_nee);
sky_light = glms_vec3_scale(sky_light, weight);
}
accumulated_color = glms_vec3_add(accumulated_color, sky_light); // TODO: Skybox
break;
}
// Add the emission of the hit material to the accumulated color
material_t* hit_material = &materials->buffer[triangles->buffer[closest_hit.triangle_id].material_id];
vec3s emission = hit_material->emission;
accumulated_color = glms_vec3_add(accumulated_color, glms_vec3_mul(throughput, emission));
light_shading_context_t light_context = {
.normal = closest_hit.normal,
.hit_point = closest_hit.point,
.wo = active_ray.direction,
.throughput = throughput,
.triangles = triangles,
.material = hit_material
};
// Running the light loop.
// TODO: Implementing other light types.
for (uint32_t i = 0; i < lights->directional_light_count; i++)
{
vec3s l = evaluate_bsdf_directional(lights->directional_lights[i], &light_context, &sobol_state);
accumulated_color = glms_vec3_add(accumulated_color, l);
}
vec3s sky_light = evaluate_bsdf_sky(scene, &light_context, &sobol_state);
accumulated_color = glms_vec3_add(accumulated_color, sky_light);
// Bounce and prepare for the next iteration
vec3s wo = glms_vec3_negate(active_ray.direction); // We need to negate the direction of the incoming ray
vec3s wi = sample_material_bsdf(hit_material, closest_hit.normal, wo, &sobol_state, &pdf_bsdf);
if (pdf_bsdf <= 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_bsdf));
// 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
}
// Keep the energy of the path by scaling the throughput
throughput = glms_vec3_scale(throughput, 1.0f / q);
}
active_ray.origin = glms_vec3_add(closest_hit.point, glms_vec3_scale(closest_hit.normal, FLT_EPSILON));
active_ray.direction = wi;
prev_normal = closest_hit.normal;
depth++;
}
return accumulated_color;
}