Finalise implementing triangle clipping
This commit is contained in:
parent
00e7293b28
commit
f6f2483b61
@ -8,10 +8,12 @@
|
|||||||
#include "vector/vec.h"
|
#include "vector/vec.h"
|
||||||
#include "window/window.h"
|
#include "window/window.h"
|
||||||
|
|
||||||
|
#define INVALID_VERTEX -1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u64 idx0;
|
i64 idx0;
|
||||||
u64 idx1;
|
i64 idx1;
|
||||||
u64 idx2;
|
i64 idx2;
|
||||||
colour_t colour;
|
colour_t colour;
|
||||||
} scene_triangle_t;
|
} scene_triangle_t;
|
||||||
|
|
||||||
@ -41,8 +43,6 @@ typedef struct {
|
|||||||
list_scene_triangle_t *triangles;
|
list_scene_triangle_t *triangles;
|
||||||
} model_t;
|
} model_t;
|
||||||
#define NULL_MODEL ((model_t){0})
|
#define NULL_MODEL ((model_t){0})
|
||||||
#define IS_NULL_MODEL(MODEL_PTR) \
|
|
||||||
(MODEL_PTR->vertices == NULL && MODEL_PTR->triangles == NULL)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
f32 scale;
|
f32 scale;
|
||||||
@ -79,5 +79,6 @@ 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_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
|
||||||
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
|
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
|
||||||
void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour);
|
void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour);
|
||||||
|
bool is_null_model(const model_t *model);
|
||||||
|
|
||||||
#endif // !RASTERISER_H
|
#endif // !RASTERISER_H
|
||||||
|
@ -15,18 +15,24 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
|
|||||||
Arena *arena, mat4x4f_t camera_matrix,
|
Arena *arena, mat4x4f_t camera_matrix,
|
||||||
mat3x4f_t projection_matrix,
|
mat3x4f_t projection_matrix,
|
||||||
const instance_t *instance);
|
const instance_t *instance);
|
||||||
internal void clip_instance(model_t *model, const rasteriser_scene_t *scene);
|
internal void clip_instance(Arena *arena, model_t *model,
|
||||||
internal void clip_instance_against_plane(model_t *model,
|
const rasteriser_scene_t *scene);
|
||||||
|
internal void clip_instance_against_plane(Arena *arena, model_t *model,
|
||||||
const bounding_sphere_t *sphere,
|
const bounding_sphere_t *sphere,
|
||||||
const clipping_plane_t *plane);
|
const clipping_plane_t *plane);
|
||||||
internal void clip_triangles_against_plane(model_t *model,
|
internal void clip_triangles_against_plane(Arena *arena, model_t *model,
|
||||||
const clipping_plane_t *plane);
|
const clipping_plane_t *plane);
|
||||||
internal void clip_triangle_against_plane(vec3f_t *v0, vec3f_t *v1, vec3f_t *v2,
|
internal void clip_triangle_against_plane(Arena *arena, model_t *model,
|
||||||
|
i64 triangle_index,
|
||||||
const clipping_plane_t *plane);
|
const clipping_plane_t *plane);
|
||||||
internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1);
|
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 void order_triangle_points(triangle_t *triangle);
|
||||||
internal inline bounding_sphere_t
|
internal inline bounding_sphere_t
|
||||||
get_bounding_sphere(const list_vec3f_t *vertices);
|
get_bounding_sphere(const list_vec3f_t *vertices);
|
||||||
|
internal inline vec3f_t segment_intersection(const vec3f_t *a, const vec3f_t *b,
|
||||||
|
const clipping_plane_t *plane);
|
||||||
|
internal inline void copy_triangles(Arena *arena, list_scene_triangle_t *dst,
|
||||||
|
const list_scene_triangle_t *src);
|
||||||
internal inline f32 signed_distance(const vec3f_t *vertex,
|
internal inline f32 signed_distance(const vec3f_t *vertex,
|
||||||
const clipping_plane_t *plane);
|
const clipping_plane_t *plane);
|
||||||
|
|
||||||
@ -50,11 +56,17 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
|
|||||||
mat3x4f_t projection_matrix,
|
mat3x4f_t projection_matrix,
|
||||||
const instance_t *instance) {
|
const instance_t *instance) {
|
||||||
list_vec3f_t *transformed = list_create_with_capacity(
|
list_vec3f_t *transformed = list_create_with_capacity(
|
||||||
vec3f_t, arena, instance->model->vertices->count * sizeof(vec3f_t));
|
vec3f_t, arena,
|
||||||
if (!transformed) {
|
(instance->model->vertices->count + 10) * sizeof(vec3f_t));
|
||||||
|
list_scene_triangle_t *triangles = list_create_with_capacity(
|
||||||
|
scene_triangle_t, arena,
|
||||||
|
(instance->model->triangles->count + 10) * sizeof(scene_triangle_t));
|
||||||
|
if (!transformed || !triangles) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy_triangles(arena, triangles, instance->model->triangles);
|
||||||
|
|
||||||
mat4x4f_t t_mat = get_translation_matrix(instance->transform.position);
|
mat4x4f_t t_mat = get_translation_matrix(instance->transform.position);
|
||||||
mat4x4f_t r_mat = get_rotation_matrix(instance->transform.rotation);
|
mat4x4f_t r_mat = get_rotation_matrix(instance->transform.rotation);
|
||||||
mat4x4f_t s_mat = get_scaling_matrix((vec3f_t){instance->transform.scale,
|
mat4x4f_t s_mat = get_scaling_matrix((vec3f_t){instance->transform.scale,
|
||||||
@ -79,10 +91,9 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
|
|||||||
list_append(vec3f_t, arena, transformed, vertex);
|
list_append(vec3f_t, arena, transformed, vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
model_t model = {transformed, instance->model->triangles};
|
model_t model = {transformed, triangles};
|
||||||
clip_instance(&model, scene);
|
clip_instance(arena, &model, scene);
|
||||||
model_t *mdl = &model;
|
if (is_null_model(&model)) {
|
||||||
if (IS_NULL_MODEL(mdl)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +112,9 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
|
|||||||
list_append(vec2i_t, arena, projected, point);
|
list_append(vec2i_t, arena, projected, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u64 i = 0; i < instance->model->triangles->count; ++i) {
|
for (u64 i = 0; i < triangles->count; ++i) {
|
||||||
scene_triangle_t triangle = list_get(instance->model->triangles, i);
|
scene_triangle_t triangle = list_get(triangles, i);
|
||||||
|
|
||||||
triangle_t tri = {
|
triangle_t tri = {
|
||||||
.p0 = list_get(projected, triangle.idx0),
|
.p0 = list_get(projected, triangle.idx0),
|
||||||
.p1 = list_get(projected, triangle.idx1),
|
.p1 = list_get(projected, triangle.idx1),
|
||||||
@ -112,6 +124,12 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
|
|||||||
.h2 = 1.0f,
|
.h2 = 1.0f,
|
||||||
.colour = triangle.colour,
|
.colour = triangle.colour,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ((tri.p0.x == tri.p1.x && tri.p0.x == tri.p2.x) &&
|
||||||
|
(tri.p0.y == tri.p1.y && tri.p0.y == tri.p2.y)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
draw_wireframe_triangle(wnd, arena, tri);
|
draw_wireframe_triangle(wnd, arena, tri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,20 +287,25 @@ 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) {
|
bool is_null_model(const model_t *model) {
|
||||||
|
return model->vertices == NULL && model->triangles == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void clip_instance(Arena *arena, model_t *model,
|
||||||
|
const rasteriser_scene_t *scene) {
|
||||||
bounding_sphere_t sphere = get_bounding_sphere(model->vertices);
|
bounding_sphere_t sphere = get_bounding_sphere(model->vertices);
|
||||||
const clipping_plane_t *plane = NULL;
|
const clipping_plane_t *plane = NULL;
|
||||||
|
|
||||||
for (u64 i = 0; i < CLIPPING_PLANE_COUNT; ++i) {
|
for (u64 i = 0; i < CLIPPING_PLANE_COUNT; ++i) {
|
||||||
plane = &(scene->planes[i]);
|
plane = &(scene->planes[i]);
|
||||||
clip_instance_against_plane(model, &sphere, plane);
|
clip_instance_against_plane(arena, model, &sphere, plane);
|
||||||
if (IS_NULL_MODEL(model)) {
|
if (is_null_model(model)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void clip_instance_against_plane(model_t *model,
|
internal void clip_instance_against_plane(Arena *arena, model_t *model,
|
||||||
const bounding_sphere_t *sphere,
|
const bounding_sphere_t *sphere,
|
||||||
const clipping_plane_t *plane) {
|
const clipping_plane_t *plane) {
|
||||||
f32 distance = signed_distance(&(sphere->centre), plane);
|
f32 distance = signed_distance(&(sphere->centre), plane);
|
||||||
@ -293,28 +316,111 @@ internal void clip_instance_against_plane(model_t *model,
|
|||||||
} else if (distance < neg_radius) {
|
} else if (distance < neg_radius) {
|
||||||
*model = NULL_MODEL;
|
*model = NULL_MODEL;
|
||||||
} else {
|
} else {
|
||||||
clip_triangles_against_plane(model, plane);
|
clip_triangles_against_plane(arena, model, plane);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void clip_triangles_against_plane(model_t *model,
|
internal void clip_triangles_against_plane(Arena *arena, model_t *model,
|
||||||
const clipping_plane_t *plane) {
|
const clipping_plane_t *plane) {
|
||||||
for (u64 i = 0; i < model->triangles->count; ++i) {
|
u64 count = model->triangles->count;
|
||||||
scene_triangle_t triangle = list_get(model->triangles, i);
|
for (u64 i = 0; i < count; ++i) {
|
||||||
vec3f_t *v0 = &(list_get(model->vertices, triangle.idx0));
|
clip_triangle_against_plane(arena, model, i, plane);
|
||||||
vec3f_t *v1 = &(list_get(model->vertices, triangle.idx1));
|
|
||||||
vec3f_t *v2 = &(list_get(model->vertices, triangle.idx2));
|
|
||||||
clip_triangle_against_plane(v0, v1, v2, plane);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void clip_triangle_against_plane(vec3f_t *v0, vec3f_t *v1, vec3f_t *v2,
|
internal void clip_triangle_against_plane(Arena *arena, model_t *model,
|
||||||
|
i64 triangle_index,
|
||||||
const clipping_plane_t *plane) {
|
const clipping_plane_t *plane) {
|
||||||
|
scene_triangle_t *triangle = &(list_get(model->triangles, triangle_index));
|
||||||
|
vec3f_t *v0 = &(list_get(model->vertices, triangle->idx0));
|
||||||
|
vec3f_t *v1 = &(list_get(model->vertices, triangle->idx1));
|
||||||
|
vec3f_t *v2 = &(list_get(model->vertices, triangle->idx2));
|
||||||
|
|
||||||
f32 d0 = signed_distance(v0, plane);
|
f32 d0 = signed_distance(v0, plane);
|
||||||
f32 d1 = signed_distance(v1, plane);
|
f32 d1 = signed_distance(v1, plane);
|
||||||
f32 d2 = signed_distance(v2, plane);
|
f32 d2 = signed_distance(v2, plane);
|
||||||
|
|
||||||
if (d0 > 0.0f && d1 > 0.0f && d2 > 0.0f) {
|
if (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f) {
|
||||||
|
return;
|
||||||
|
} else if (d0 < 0.0f && d1 < 0.0f && d2 < 0.0f) {
|
||||||
|
triangle->idx0 = INVALID_VERTEX;
|
||||||
|
triangle->idx1 = INVALID_VERTEX;
|
||||||
|
triangle->idx2 = INVALID_VERTEX;
|
||||||
|
} else if ((d0 < 0.0f && d1 < 0.0f) || (d0 < 0.0f && d2 < 0.0f) ||
|
||||||
|
(d1 < 0.0f && d2 < 0.0f)) {
|
||||||
|
vec3f_t *vp;
|
||||||
|
vec3f_t *vn0;
|
||||||
|
vec3f_t *vn1;
|
||||||
|
i64 *in0;
|
||||||
|
i64 *in1;
|
||||||
|
if (d0 > 0.0f) {
|
||||||
|
vp = v0;
|
||||||
|
vn0 = v1;
|
||||||
|
vn1 = v2;
|
||||||
|
in0 = &(triangle->idx1);
|
||||||
|
in1 = &(triangle->idx2);
|
||||||
|
} else if (d1 > 0.0f) {
|
||||||
|
vp = v1;
|
||||||
|
vn0 = v0;
|
||||||
|
vn1 = v2;
|
||||||
|
in0 = &(triangle->idx0);
|
||||||
|
in1 = &(triangle->idx2);
|
||||||
|
} else {
|
||||||
|
vp = v2;
|
||||||
|
vn0 = v0;
|
||||||
|
vn1 = v1;
|
||||||
|
in0 = &(triangle->idx0);
|
||||||
|
in1 = &(triangle->idx1);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_append(vec3f_t, arena, model->vertices,
|
||||||
|
segment_intersection(vp, vn0, plane));
|
||||||
|
list_append(vec3f_t, arena, model->vertices,
|
||||||
|
segment_intersection(vp, vn1, plane));
|
||||||
|
|
||||||
|
*in0 = model->vertices->count - 2;
|
||||||
|
*in1 = model->vertices->count - 1;
|
||||||
|
} else {
|
||||||
|
vec3f_t *vn;
|
||||||
|
vec3f_t *vp0;
|
||||||
|
vec3f_t *vp1;
|
||||||
|
i64 *in;
|
||||||
|
i64 *ip;
|
||||||
|
if (d0 < 0.0f) {
|
||||||
|
vn = v0;
|
||||||
|
vp0 = v1;
|
||||||
|
vp1 = v2;
|
||||||
|
in = &(triangle->idx0);
|
||||||
|
ip = &(triangle->idx2);
|
||||||
|
} else if (d1 < 0.0f) {
|
||||||
|
vn = v1;
|
||||||
|
vp0 = v0;
|
||||||
|
vp1 = v2;
|
||||||
|
in = &(triangle->idx1);
|
||||||
|
ip = &(triangle->idx2);
|
||||||
|
} else {
|
||||||
|
vn = v2;
|
||||||
|
vp0 = v0;
|
||||||
|
vp1 = v1;
|
||||||
|
in = &(triangle->idx2);
|
||||||
|
ip = &(triangle->idx1);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_append(vec3f_t, arena, model->vertices,
|
||||||
|
segment_intersection(vp0, vn, plane));
|
||||||
|
list_append(vec3f_t, arena, model->vertices,
|
||||||
|
segment_intersection(vp1, vn, plane));
|
||||||
|
|
||||||
|
*in = model->vertices->count - 2;
|
||||||
|
|
||||||
|
scene_triangle_t tri = {
|
||||||
|
.idx0 = *in,
|
||||||
|
.idx1 = *ip,
|
||||||
|
.idx2 = model->vertices->count - 1,
|
||||||
|
.colour = triangle->colour,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_append(scene_triangle_t, arena, model->triangles, tri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,8 +489,28 @@ get_bounding_sphere(const list_vec3f_t *vertices) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal inline vec3f_t segment_intersection(const vec3f_t *a, const vec3f_t *b,
|
||||||
|
const clipping_plane_t *plane) {
|
||||||
|
f32 neg_d = plane->distance * -1.0f;
|
||||||
|
f32 na_dot = vec_dot(vec3f_t, plane->normal, *a);
|
||||||
|
vec3f_t ba = vec_sub(vec3f_t, *b, *a);
|
||||||
|
f32 nba_dot = vec_dot(vec3f_t, plane->normal, ba);
|
||||||
|
|
||||||
|
f32 t = (neg_d - na_dot) / nba_dot;
|
||||||
|
|
||||||
|
return vec_add(vec3f_t, *a, vec_mul_num(vec3f_t, ba, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline void copy_triangles(Arena *arena, list_scene_triangle_t *dst,
|
||||||
|
const list_scene_triangle_t *src) {
|
||||||
|
for (u64 i = 0; i < src->count; ++i) {
|
||||||
|
scene_triangle_t tri = list_get(src, i);
|
||||||
|
list_append(scene_triangle_t, arena, dst, tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal inline f32 signed_distance(const vec3f_t *vertex,
|
internal inline f32 signed_distance(const vec3f_t *vertex,
|
||||||
const clipping_plane_t *plane) {
|
const clipping_plane_t *plane) {
|
||||||
return (vertex->x * plane->normal.x) + (vertex->y + plane->normal.y) +
|
return (vertex->x * plane->normal.x) + (vertex->y * plane->normal.y) +
|
||||||
(vertex->z + plane->normal.z) + plane->distance;
|
(vertex->z * plane->normal.z) + plane->distance;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user