Files
SimpleRayTracing/source/Rendering/Scene.c
Misaki 6800810369 Update project structure and improve performance
Added new files for BVH, AABB, and Debug functionalities.
Added new utility functions in Common.h.
Added gamma correction function in PostProcessing.h.
Changed the return type of path_trace to vec4s for alpha blending.
Changed BSDF function signatures to include sample index and bounce.
Changed the BSDF.h to replace inline functions with declarations.
Changed the Light and SkyLight evaluation functions to include throughput and sample index.
Changed the sphere creation function in GeometryUtilities.h for better quality.
Changed the scene structure to include a BVH tree for improved ray intersection.
Changed the scene initialization parameters for better performance.
Created new Debug functions for ray intersection counting.
Created new functions for triangle collection management in Triangle.c.
Improved pixel updating logic in Window.c.
Improved ray intersection performance with new BVH implementation.
Removed unused includes from Common.h.
Removed old library linking methods in CMakeLists.txt.
2025-04-21 15:56:19 +09:00

260 lines
8.3 KiB
C

#include "Debug.h"
#include "Rendering/Scene.h"
#include "Algorithm/PathTracing.h"
#define FLIP_Y
bool scene_init(uint64_t triangle_count, uint8_t material_count, uint32_t punctual_light_count, scene_t* scene)
{
scene_t temp = {0};
if (!triangle_collection_init(triangle_count, &temp.triangles))
{
goto triangle_failed;
}
if (!material_collection_init(material_count, &temp.materials))
{
goto material_failed;
}
if (!light_collection_create(punctual_light_count, 16, &temp.lights)) // NOTE: We just fixed the max directional light count to 16.
{
goto light_failed;
}
temp.camera = camera_create(
(vec3s){0.0f, 0.0f, 5.0f},
(vec3s){0.0f, 0.0f, -1.0f},
(vec3s){0.0f, 1.0f, 0.0f},
0.025f,
0.036f,
16.0f / 9.0f
);
*scene = temp;
return true;
light_failed:
material_collection_free(&temp.materials);
material_failed:
triangle_collection_free(&temp.triangles);
triangle_failed:
return false;
}
void scene_free(scene_t* scene)
{
bvh_tree_free(&scene->bvh_tree);
triangle_collection_free(&scene->triangles);
material_collection_free(&scene->materials);
light_collection_free(&scene->lights);
}
bool scene_build_bvh(scene_t* scene)
{
if (scene == NULL || scene->triangles.count == 0)
{
return false;
}
bvh_tree_t bvh_tree = {0};
if (!bvh_tree_init(&bvh_tree, &scene->triangles))
{
return false;
}
bvh_tree_build(&bvh_tree);
scene->bvh_tree = bvh_tree;
return true;
}
static inline void ensure_camera_aspect_ratio(camera_t* camera, rendering_config_t config)
{
if (fabsf((float)config.width / config.height - camera->aspect_ratio) > FLT_EPSILON)
{
*camera = camera_create(
camera->position,
camera->forward,
camera->up,
camera->focal_length,
camera->size_x,
(float)config.width / (float)config.height
);
}
}
static inline vec2s compute_ndc(float x, float y, uint32_t width, uint32_t height)
{
return (vec2s){
.x = x / (float)width,
#ifdef FLIP_Y
.y = 1.0f - y / (float)height
#else
.y = y / (float)height
#endif
};
}
static inline uint16_t get_sample_count(uint16_t sample_count, int flag)
{
switch (flag)
{
case DEBUG_BVH:
case DEBUG_SOBOL:
return 1;
default:
return sample_count;
}
return sample_count;
}
static void screen_render_pixel(scene_t* scene, rendering_config_t config, vec3s coord, uint32_t x, uint32_t y, int flag, vec4s* pixel_color)
{
vec4s accumulated_color = glms_vec4_zero();
*pixel_color = accumulated_color;
uint32_t pixel_id = y * config.width + x;
uint16_t sample_count = get_sample_count(config.sample_count, flag);
for (uint16_t k = 0; k < sample_count; k++)
{
vec2s position_ndc = compute_ndc((float)x, (float)y, config.width, config.height);
float screen_x = position_ndc.x * 2.0f - 1.0f;
float screen_y = position_ndc.y * 2.0f - 1.0f;
float sensor_offset_x = screen_x * scene->camera.size_x / 2.0f;
float sensor_offset_y = screen_y * scene->camera.size_y / 2.0f;
vec3s image_plane_point = coord;
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(scene->camera.right, sensor_offset_x));
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(scene->camera.up, sensor_offset_y));
ray_t ray = {
.origin = scene->camera.position,
.direction = glms_vec3_normalize(glms_vec3_sub(image_plane_point, scene->camera.position))
};
vec4s out_color = glms_vec4_zero();
if (flag != 0)
{
out_color = render_debug(scene, ray, k, flag);
}
else
{
// TODO: Hash it
uint32_t sobol_idx = pixel_id * config.sample_count + (k + 1);
out_color = path_trace(scene, ray, sobol_idx, config.max_depth);
}
accumulated_color = glms_vec4_add(accumulated_color, out_color);
}
*pixel_color = glms_vec4_scale(accumulated_color, 1.0f / (float)sample_count);
}
bool scene_render_tile(scene_t* scene, rendering_context_t* ctx, rendering_config_t config, uint32_t tile_index, int rendering_flag, render_target_t* render_target, tile_t* tile_out)
{
if (ctx->is_done)
{
return false;
}
if(!ctx->is_init)
{
ensure_camera_aspect_ratio(&scene->camera, config);
ctx->tile_count_x = (config.width + config.bucket_size - 1) / config.bucket_size;
ctx->tile_count_y = (config.height + config.bucket_size - 1) / config.bucket_size;
ctx->coord = glms_vec3_add(scene->camera.position, glms_vec3_scale(scene->camera.forward, scene->camera.focal_length));
ctx->is_init = true;
}
if (tile_index >= ctx->tile_count_x * ctx->tile_count_y)
{
return false;
}
uint32_t tile_x_0 = tile_index % ctx->tile_count_x * config.bucket_size;
uint32_t tile_y_0 = tile_index / ctx->tile_count_x * config.bucket_size;
uint32_t tile_x_1 = (uint32_t)fmin(tile_x_0 + config.bucket_size, config.width);
uint32_t tile_y_1 = (uint32_t)fmin(tile_y_0 + config.bucket_size, config.height);
tile_out->x = tile_x_0;
tile_out->y = tile_y_0;
tile_out->width = tile_x_1 - tile_x_0;
tile_out->height = tile_y_1 - tile_y_0;
int64_t x, y; // OpenMP requires these to be declared outside the parallel region. Also, they need to be signed integers. To avoid overflow, we need to use int64_t
rendering_config_t config_copy = config; // Have to copy it, otherwise OpenMP will cause it become invalid. Not sure if this is a bug or not.
#pragma omp parallel for schedule(dynamic, 1) default(none) \
shared(tile_x_0, tile_x_1, tile_y_0, tile_y_1, config_copy) \
private(x, y)
for (y = tile_y_0; y < tile_y_1; y++)
{
for (x = tile_x_0; x < tile_x_1; x++)
{
vec4s pixel_color;
screen_render_pixel(scene, config_copy, ctx->coord, (uint32_t)x, (uint32_t)y, rendering_flag, &pixel_color);
render_target_set_pixel(render_target, (uint32_t)x, (uint32_t)y, pixel_color);
}
}
if (tile_index == ctx->tile_count_x * ctx->tile_count_y - 1)
{
ctx->is_done = true;
}
return true;
}
bool scene_render(scene_t* scene, rendering_config_t config, int rendering_flag, render_target_t* render_target)
{
ensure_camera_aspect_ratio(&scene->camera, config);
if (render_target->buffer != NULL)
{
render_target_free(render_target);
}
if (render_target_init(config.width, config.height, render_target))
{
return false;
}
uint32_t tile_count_x = (config.width + config.bucket_size - 1) / config.bucket_size;
uint32_t tile_count_y = (config.height + config.bucket_size - 1) / config.bucket_size;
uint32_t tile_count = tile_count_x * tile_count_y;
float inv_sample = 1.0f / config.sample_count;
vec3s coord = glms_vec3_add(scene->camera.position, glms_vec3_scale(scene->camera.forward, scene->camera.focal_length));
int64_t x, y, tile_index; // OpenMP requires these to be declared outside the parallel region. Also, they need to be signed integers. To avoid overflow, we need to use int64_t
rendering_config_t config_copy = config;
#pragma omp parallel for schedule(dynamic, 1) default(none) \
shared(tile_count_x, tile_count_y, tile_count, config_copy, coord, inv_sample, render_target) \
private(x, y, tile_index)
for (tile_index = 0; tile_index < tile_count; tile_index++)
{
uint32_t tile_x_0 = (uint32_t)tile_index % tile_count_x * config.bucket_size;
uint32_t tile_y_0 = (uint32_t)tile_index / tile_count_x * config.bucket_size;
uint32_t tile_x_1 = (uint32_t)fmin(tile_x_0 + config.bucket_size, config.width);
uint32_t tile_y_1 = (uint32_t)fmin(tile_y_0 + config.bucket_size, config.height);
for (y = tile_y_0; y < tile_y_1; y++)
{
for (x = tile_x_0; x < tile_x_1; x++)
{
vec4s pixel_color;
screen_render_pixel(scene, config_copy, coord, (uint32_t)x, (uint32_t)y, rendering_flag, &pixel_color);
render_target_set_pixel(render_target, (uint32_t)x, (uint32_t)y, pixel_color);
}
}
}
return true;
}