Update project files and enhance rendering system

Added:
- Updated `.gitignore` to ignore the `[Bb]uild/` directory.
- Additional tasks added to the roadmap in `README.md` for light unit standardization and GPU backend support.

Changed:
- Removed line in `settings.json` that disabled error squiggles for C/C++ code.
- Modified `Triangle.h` to include `material_id` in `triangle_t` and reorganized properties.
- Reordered parameters in `triangle_collection_init` for clarity.
- Updated `shading_context_t` in `Material.h` and added size parameter to `material_create`.
- Streamlined initialization in `scene_init` and updated `scene_free` for proper resource management.
- Updated `window_create` in `Window.h` to accept a `render_job_t` parameter.
- Introduced `renderer_start` in `Renderer.c` to handle rendering jobs and optimized pixel rendering logic.
This commit is contained in:
2025-04-23 22:24:02 +09:00
parent 9cc420693c
commit 17872804c5
24 changed files with 523083 additions and 807 deletions

129
source/Rendering/Renderer.c Normal file
View File

@@ -0,0 +1,129 @@
#include "Rendering/Renderer.h"
#include "Algorithm/PathTracing.h"
#define FLIP_Y
static inline void ensure_camera_aspect_ratio(camera_t* camera, const rendering_config_t* config)
{
float aspect_ratio = (float)config->width / config->height;
if (fabsf((float)config->width / config->height - camera->size_x / camera->size_y) > 0.001f)
{
camera->size_y = camera->size_x / aspect_ratio;
camera->fov_y = 2.0f * (float)atan(camera->size_x / (2.0f * camera->focal_length * aspect_ratio));
}
}
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 render_pixel(const rendering_config_t* config, scene_t* scene, vec3s coord, uint32_t x, uint32_t y, int flag, vec4s* pixel_color)
{
vec4s accumulated_color = glms_vec4_zero();
uint32_t pixel_id = y * config->width + x;
uint16_t sample_count = get_sample_count(config->sample_count, flag);
vec2s position_ndc = compute_ndc((float)x, (float)y, config->width, config->height);
vec3s camera_right = quat_get_right(scene->camera.rotation);
vec3s camera_up = quat_get_up(scene->camera.rotation);
for (uint16_t k = 0; k < sample_count; k++)
{
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 * 0.5f;
float sensor_offset_y = screen_y * scene->camera.size_y * 0.5f;
vec3s image_plane_point = coord;
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(camera_right, sensor_offset_x));
image_plane_point = glms_vec3_add(image_plane_point, glms_vec3_scale(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);
}
// TODO: Progressive rendering
void renderer_start(render_job_t* job)
{
ensure_camera_aspect_ratio(&job->scene->camera, job->config);
uint32_t tile_count_x = (job->config->width + job->config->bucket_size - 1) / job->config->bucket_size;
uint32_t tile_count_y = (job->config->height + job->config->bucket_size - 1) / job->config->bucket_size;
uint32_t tile_count = tile_count_x * tile_count_y;
float inv_sample = 1.0f / job->config->sample_count;
vec3s coord = glms_vec3_add(job->scene->camera.position, glms_vec3_scale(quat_get_forward(job->scene->camera.rotation), job->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
#pragma omp parallel for schedule(dynamic, 1) default(none) \
shared(tile_count_x, tile_count_y, tile_count, coord, inv_sample, job) \
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 * job->config->bucket_size;
uint32_t tile_y_0 = (uint32_t)tile_index / tile_count_x * job->config->bucket_size;
uint32_t tile_x_1 = (uint32_t)fmin(tile_x_0 + job->config->bucket_size, job->config->width);
uint32_t tile_y_1 = (uint32_t)fmin(tile_y_0 + job->config->bucket_size, job->config->height);
for (y = tile_y_0; y < tile_y_1; y++)
{
for (x = tile_x_0; x < tile_x_1; x++)
{
if (job->is_done)
{
goto tile_done;
}
vec4s pixel_color;
render_pixel(job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, job->rendering_flag, &pixel_color);
render_target_set_pixel(job->render_target, (uint32_t)x, (uint32_t)y, pixel_color);
}
}
tile_done:;
}
job->is_done = true;
}