Initial implementation of bounding sphere clipping

This commit is contained in:
Abdelrahman Said 2024-07-09 23:31:54 +01:00
parent c3e1aac779
commit ae072ec70e
3 changed files with 114 additions and 39 deletions
include/rasteriser
src/rasteriser

@ -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);

@ -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,
},
},
};

@ -11,8 +11,17 @@
#include <string.h>
#include <sys/mman.h>
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;
}