From ae072ec70e52b4fb15bbffca1be72024f9d16144 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Tue, 9 Jul 2024 23:31:54 +0100 Subject: [PATCH] Initial implementation of bounding sphere clipping --- include/rasteriser/rasteriser.h | 16 ++++--- src/rasteriser/main.c | 53 +++++++++++---------- src/rasteriser/rasteriser.c | 84 +++++++++++++++++++++++++++++---- 3 files changed, 114 insertions(+), 39 deletions(-) diff --git a/include/rasteriser/rasteriser.h b/include/rasteriser/rasteriser.h index a2a0769..f294f6a 100644 --- a/include/rasteriser/rasteriser.h +++ b/include/rasteriser/rasteriser.h @@ -40,6 +40,8 @@ typedef struct { list_vec3f_t *vertices; list_scene_triangle_t *triangles; } model_t; +#define NULL_MODEL ((model_t){0}) +#define IS_NULL_MODEL(MODEL) (MODEL.vertices == NULL && MODEL.triangles == NULL) typedef struct { f32 scale; @@ -47,6 +49,11 @@ typedef struct { vec3f_t position; } transform_t; +typedef struct { + vec3f_t centre; + f32 radius; +} bounding_sphere_t; + typedef struct { model_t *model; transform_t transform; @@ -57,21 +64,16 @@ typedef struct { f32 distance; } clipping_plane_t; +#define CLIPPING_PLANE_COUNT 5 typedef struct { u64 instance_count; instance_t *instances; camera_t *camera; const mat3x4f_t *proj_matrix; - clipping_plane_t near; - clipping_plane_t left; - clipping_plane_t right; - clipping_plane_t bottom; - clipping_plane_t top; + clipping_plane_t planes[CLIPPING_PLANE_COUNT]; } rasteriser_scene_t; void render_scene(window_t *wnd, Arena *arena, const rasteriser_scene_t *scene); -void render_instance(window_t *wnd, Arena *arena, mat4x4f_t camera_matrix, - mat3x4f_t projection_matrix, const instance_t *instance); void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle); void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle); void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle); diff --git a/src/rasteriser/main.c b/src/rasteriser/main.c index fb818b6..8d8a897 100644 --- a/src/rasteriser/main.c +++ b/src/rasteriser/main.c @@ -107,30 +107,35 @@ int main(void) { .instances = instances, .camera = &camera, .proj_matrix = &proj_matrix, - .near = - (clipping_plane_t){ - .normal = (vec3f_t){0.0f, 0.0f, 1.0f}, - .distance = viewport.z, - }, - .left = - (clipping_plane_t){ - .normal = (vec3f_t){one_div_sqrt_2, 0.0f, one_div_sqrt_2}, - .distance = 0.0f, - }, - .right = - (clipping_plane_t){ - .normal = (vec3f_t){neg_one_div_sqrt_2, 0.0f, one_div_sqrt_2}, - .distance = 0.0f, - }, - .bottom = - (clipping_plane_t){ - .normal = (vec3f_t){0.0f, one_div_sqrt_2, one_div_sqrt_2}, - .distance = 0.0f, - }, - .top = - (clipping_plane_t){ - .normal = (vec3f_t){0.0f, neg_one_div_sqrt_2, one_div_sqrt_2}, - .distance = 0.0f, + .planes = + { + [0] = + (clipping_plane_t){ + .normal = (vec3f_t){0.0f, 0.0f, 1.0f}, + .distance = viewport.z, + }, + [1] = + (clipping_plane_t){ + .normal = (vec3f_t){one_div_sqrt_2, 0.0f, one_div_sqrt_2}, + .distance = 0.0f, + }, + [2] = + (clipping_plane_t){ + .normal = + (vec3f_t){neg_one_div_sqrt_2, 0.0f, one_div_sqrt_2}, + .distance = 0.0f, + }, + [3] = + (clipping_plane_t){ + .normal = (vec3f_t){0.0f, one_div_sqrt_2, one_div_sqrt_2}, + .distance = 0.0f, + }, + [4] = + (clipping_plane_t){ + .normal = + (vec3f_t){0.0f, neg_one_div_sqrt_2, one_div_sqrt_2}, + .distance = 0.0f, + }, }, }; diff --git a/src/rasteriser/rasteriser.c b/src/rasteriser/rasteriser.c index 25c7abe..4bb08bc 100644 --- a/src/rasteriser/rasteriser.c +++ b/src/rasteriser/rasteriser.c @@ -11,8 +11,17 @@ #include #include +internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, + Arena *arena, mat4x4f_t camera_matrix, + mat3x4f_t projection_matrix, + const instance_t *instance); +internal void clip_instance(model_t *model, const rasteriser_scene_t *scene); internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1); internal inline void order_triangle_points(triangle_t *triangle); +internal inline bounding_sphere_t +get_bounding_sphere(const list_vec3f_t *vertices); +internal inline f32 signed_distance(const vec3f_t *vertex, + const clipping_plane_t *plane); void render_scene(window_t *wnd, Arena *arena, const rasteriser_scene_t *scene) { @@ -24,15 +33,17 @@ void render_scene(window_t *wnd, Arena *arena, mul_mat4x4f(cam_inverse_rotation, cam_inverse_translation); for (u64 i = 0; i < scene->instance_count; ++i) { - render_instance(wnd, arena, cam_matrix, *(scene->proj_matrix), + render_instance(wnd, scene, arena, cam_matrix, *(scene->proj_matrix), &(scene->instances[i])); } } -void render_instance(window_t *wnd, Arena *arena, mat4x4f_t camera_matrix, - mat3x4f_t projection_matrix, const instance_t *instance) { - list_vec4f_t *transformed = list_create_with_capacity( - vec4f_t, arena, instance->model->vertices->count * sizeof(vec4f_t)); +internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, + Arena *arena, mat4x4f_t camera_matrix, + mat3x4f_t projection_matrix, + const instance_t *instance) { + list_vec3f_t *transformed = list_create_with_capacity( + vec3f_t, arena, instance->model->vertices->count * sizeof(vec3f_t)); if (!transformed) { return; } @@ -51,9 +62,20 @@ void render_instance(window_t *wnd, Arena *arena, mat4x4f_t camera_matrix, vec4f_t xf_vertex = {0}; for (u64 i = 0; i < instance->model->vertices->count; ++i) { vertex = list_get(instance->model->vertices, i); + xf_vertex = mul_mat4x4f_by_vec4f( xf_cam_mat, (vec4f_t){vertex.x, vertex.y, vertex.z, 1.0f}); - list_append(vec4f_t, arena, transformed, xf_vertex); + xf_vertex = vec_div_num(vec4f_t, xf_vertex, xf_vertex.w); + + vertex = (vec3f_t){xf_vertex.x, xf_vertex.y, xf_vertex.z}; + + list_append(vec3f_t, arena, transformed, vertex); + } + + model_t model = {transformed, instance->model->triangles}; + clip_instance(&model, scene); + if (IS_NULL_MODEL(model)) { + return; } list_vec2i_t *projected = list_create_with_capacity( @@ -64,8 +86,9 @@ void render_instance(window_t *wnd, Arena *arena, mat4x4f_t camera_matrix, vec2i_t point = {0}; for (u64 i = 0; i < transformed->count; ++i) { - xf_vertex = list_get(transformed, i); - vertex = mul_mat3x4f_by_vec4f(projection_matrix, xf_vertex); + vertex = list_get(transformed, i); + vertex = mul_mat3x4f_by_vec4f( + projection_matrix, (vec4f_t){vertex.x, vertex.y, vertex.z, 1.0f}); point = (vec2i_t){(i32)(vertex.x / vertex.z), (i32)(vertex.y / vertex.z)}; list_append(vec2i_t, arena, projected, point); } @@ -238,6 +261,22 @@ void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) { } } +internal void clip_instance(model_t *model, const rasteriser_scene_t *scene) { + bounding_sphere_t sphere = get_bounding_sphere(model->vertices); + f32 distance = 0.0; + f32 neg_radius = -1.0f * sphere.radius; + const clipping_plane_t *plane = NULL; + + for (u64 i = 0; i < CLIPPING_PLANE_COUNT; ++i) { + plane = &(scene->planes[i]); + + distance = signed_distance(&(sphere.centre), plane); + if (distance < neg_radius) { + *model = NULL_MODEL; + } + } +} + internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1) { list_float *values; if (i0 == i1) { @@ -279,3 +318,32 @@ internal inline void order_triangle_points(triangle_t *triangle) { swap(f32, triangle->h1, triangle->h2); } } + +internal inline bounding_sphere_t +get_bounding_sphere(const list_vec3f_t *vertices) { + vec3f_t sum = {0}; + for (u64 i = 0; i < vertices->count; ++i) { + sum = vec_add(vec3f_t, list_get(vertices, i), sum); + } + + vec3f_t centre = vec_div_num(vec3f_t, sum, vertices->count); + f32 radius = 0.0f; + f32 tmp = 0.0f; + vec3f_t dst = {0}; + for (u64 i = 0; i < vertices->count; ++i) { + dst = vec_sub(vec3f_t, list_get(vertices, i), centre); + tmp = vec_magnitude(vec3f_t, dst); + radius = tmp > radius ? tmp : radius; + } + + return (bounding_sphere_t){ + .centre = centre, + .radius = radius, + }; +} + +internal inline f32 signed_distance(const vec3f_t *vertex, + const clipping_plane_t *plane) { + return (vertex->x * plane->normal.x) + (vertex->y + plane->normal.y) + + (vertex->z + plane->normal.z) + plane->distance; +}