Refactor camera system to use quaternion rotations

Added quaternion and vector structures from the cglm library for handling 3D rotations and directions.
Added a new function `euler_to_quat` to convert Euler angles to a quaternion representation.
Changed the `camera_t` structure to replace separate forward, up, and right vectors with a single rotation quaternion.
Changed the `camera_create` function to accept a rotation quaternion instead of separate direction vectors.
Changed the `scene_init` function to initialize the camera with a default rotation quaternion.
Changed the `ensure_camera_aspect_ratio` function to maintain the camera's rotation quaternion.
Changed the `screen_render_pixel`, `scene_render_tile`, and `scene_render` functions to compute camera coordinates based on the quaternion rotation.
This commit is contained in:
2025-04-22 17:26:04 +09:00
parent e49004e6a2
commit 9cc420693c
5 changed files with 38 additions and 27 deletions

View File

@@ -25,8 +25,7 @@ bool scene_init(uint64_t triangle_count, uint8_t material_count, uint32_t punctu
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},
glms_quat_identity(),
0.025f,
0.036f,
16.0f / 9.0f
@@ -75,8 +74,7 @@ static inline void ensure_camera_aspect_ratio(camera_t* camera, rendering_confi
{
*camera = camera_create(
camera->position,
camera->forward,
camera->up,
camera->rotation,
camera->focal_length,
camera->size_x,
(float)config.width / (float)config.height
@@ -117,18 +115,20 @@ static void screen_render_pixel(scene_t* scene, rendering_config_t config, vec3s
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++)
{
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));
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,
@@ -167,7 +167,7 @@ bool scene_render_tile(scene_t* scene, rendering_context_t* ctx, rendering_confi
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->coord = glms_vec3_add(scene->camera.position, glms_vec3_scale(quat_get_forward(scene->camera.rotation), scene->camera.focal_length));
ctx->is_init = true;
}
@@ -230,7 +230,7 @@ bool scene_render(scene_t* scene, rendering_config_t config, int rendering_flag,
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));
vec3s coord = glms_vec3_add(scene->camera.position, glms_vec3_scale(quat_get_forward(scene->camera.rotation), 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;