filled triangles using z-buffer

This commit is contained in:
jasobake 2026-02-10 23:28:14 -08:00
parent 95c015d719
commit d01a33e27c
3 changed files with 131 additions and 125 deletions

View File

@ -208,9 +208,6 @@ void update(void) {
projected_points[j].y += (window_height / 2.0); projected_points[j].y += (window_height / 2.0);
} }
// Calculate the average depth for each face based on the vertices after transformation
float avg_depth = (transformed_vertices[0].z + transformed_vertices[1].z + transformed_vertices[2].z) / 3.0;
// Calculate the shade intensity based on how aliged is the normal with the flipped light direction ray // Calculate the shade intensity based on how aliged is the normal with the flipped light direction ray
float light_intensity_factor = -vec3_dot(normal, light.direction); float light_intensity_factor = -vec3_dot(normal, light.direction);
@ -229,7 +226,6 @@ void update(void) {
{ mesh_face.c_uv.u, mesh_face.c_uv.v } { mesh_face.c_uv.u, mesh_face.c_uv.v }
}, },
.color = triangle_color, .color = triangle_color,
.avg_depth = avg_depth
}; };
// Save the projected triangle in the array of triangles to render // Save the projected triangle in the array of triangles to render
@ -253,9 +249,9 @@ void render(void) {
// Draw filled triangle // Draw filled triangle
if (render_method == RENDER_FILL_TRIANGLE || render_method == RENDER_FILL_TRIANGLE_WIRE) { if (render_method == RENDER_FILL_TRIANGLE || render_method == RENDER_FILL_TRIANGLE_WIRE) {
draw_filled_triangle( draw_filled_triangle(
triangle.points[0].x, triangle.points[0].y, // vertex A triangle.points[0].x, triangle.points[0].y, triangle.points[0].z, triangle.points[0].w, // vertex A
triangle.points[1].x, triangle.points[1].y, // vertex B triangle.points[1].x, triangle.points[1].y, triangle.points[1].z, triangle.points[1].w, // vertex B
triangle.points[2].x, triangle.points[2].y, // vertex C triangle.points[2].x, triangle.points[2].y, triangle.points[2].z, triangle.points[2].w, // vertex C
triangle.color triangle.color
); );
} }

View File

@ -2,122 +2,6 @@
#include "swap.h" #include "swap.h"
#include "triangle.h" #include "triangle.h"
///////////////////////////////////////////////////////////////////////////////
// Draw a filled a triangle with a flat bottom
///////////////////////////////////////////////////////////////////////////////
//
// (x0,y0)
// / \
// / \
// / \
// / \
// / \
// (x1,y1)------(x2,y2)
//
///////////////////////////////////////////////////////////////////////////////
void fill_flat_bottom_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
// Find the two slopes (two triangle legs)
float inv_slope_1 = (float)(x1 - x0) / (y1 - y0);
float inv_slope_2 = (float)(x2 - x0) / (y2 - y0);
// Start x_start and x_end from the top vertex (x0,y0)
float x_start = x0;
float x_end = x0;
// Loop all the scanlines from top to bottom
for (int y = y0; y <= y2; y++) {
draw_line(x_start, y, x_end, y, color);
x_start += inv_slope_1;
x_end += inv_slope_2;
}
}
///////////////////////////////////////////////////////////////////////////////
// Draw a filled a triangle with a flat top
///////////////////////////////////////////////////////////////////////////////
//
// (x0,y0)------(x1,y1)
// \ /
// \ /
// \ /
// \ /
// \ /
// (x2,y2)
//
///////////////////////////////////////////////////////////////////////////////
void fill_flat_top_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
// Find the two slopes (two triangle legs)
float inv_slope_1 = (float)(x2 - x0) / (y2 - y0);
float inv_slope_2 = (float)(x2 - x1) / (y2 - y1);
// Start x_start and x_end from the bottom vertex (x2,y2)
float x_start = x2;
float x_end = x2;
// Loop all the scanlines from bottom to top
for (int y = y2; y >= y0; y--) {
draw_line(x_start, y, x_end, y, color);
x_start -= inv_slope_1;
x_end -= inv_slope_2;
}
}
///////////////////////////////////////////////////////////////////////////////
// Draw a filled triangle with the flat-top/flat-bottom method
// We split the original triangle in two, half flat-bottom and half flat-top
///////////////////////////////////////////////////////////////////////////////
//
// (x0,y0)
// / \
// / \
// / \
// / \
// / \
// (x1,y1)------(Mx,My)
// \_ \
// \_ \
// \_ \
// \_ \
// \ \
// \_ \
// \_\
// \
// (x2,y2)
//
///////////////////////////////////////////////////////////////////////////////
void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
// We need to sort the vertices by y-coordinate ascending (y0 < y1 < y2)
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
}
if (y1 > y2) {
int_swap(&y1, &y2);
int_swap(&x1, &x2);
}
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
}
if (y1 == y2) {
// Draw flat-bottom triangle
fill_flat_bottom_triangle(x0, y0, x1, y1, x2, y2, color);
} else if (y0 == y1) {
// Draw flat-top triangle
fill_flat_top_triangle(x0, y0, x1, y1, x2, y2, color);
} else {
// Calculate the new vertex (Mx,My) using triangle similarity
int My = y1;
int Mx = (((x2 - x0) * (y1 - y0)) / (y2 - y0)) + x0;
// Draw flat-bottom triangle
fill_flat_bottom_triangle(x0, y0, x1, y1, Mx, My, color);
// Draw flat-top triangle
fill_flat_top_triangle(x1, y1, Mx, My, x2, y2, color);
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Draw a triangle using three raw line calls // Draw a triangle using three raw line calls
@ -223,6 +107,46 @@ void draw_texel(
} }
} }
void draw_triangle_pixel(
int x, int y, uint32_t color,
vec4_t point_a, vec4_t point_b, vec4_t point_c
) {
vec2_t p = { x, y };
vec2_t a = vec2_from_vec4(point_a);
vec2_t b = vec2_from_vec4(point_b);
vec2_t c = vec2_from_vec4(point_c);
// Calculate the barycentric coordinates of our point 'p' inside the triangle
vec3_t weights = barycentric_weights(a, b, c, p);
float alpha = weights.x;
float beta = weights.y;
float gamma = weights.z;
// Variables to store the interpolated values of U, V, and also 1/w for the current pixel
float interpolated_reciprocal_w;
// Also interpolate the value of 1/w for the current pixel
interpolated_reciprocal_w = (1 / point_a.w) * alpha + (1 / point_b.w) * beta + (1 / point_c.w) * gamma;
// Now we can divide back both interpolated values by 1/w
//tex_x = SDL_clamp(tex_x, 0, texture_width);
//tex_y = SDL_clamp(tex_y, 0, texture_height);
int z_pos = (window_width * y) + x;
// Adjust 1/w so the pixels that are closer to the camera have smaller values
interpolated_reciprocal_w = 1.0 - interpolated_reciprocal_w;
// only draw pixel if depth value is less than one previously stored in z-buffer
if (interpolated_reciprocal_w < z_buffer[z_pos]) {
draw_pixel(x, y, color);
// update z-buffer value with the 1/w of this current pixel
z_buffer[z_pos] = interpolated_reciprocal_w;
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Draw a textured triangle based on a texture array of colors. // Draw a textured triangle based on a texture array of colors.
// We split the original triangle in two, half flat-bottom and half flat-top. // We split the original triangle in two, half flat-bottom and half flat-top.
@ -339,3 +263,85 @@ void draw_textured_triangle(
} }
} }
void draw_filled_triangle(
int x0, int y0, float z0, float w0,
int x1, int y1, float z1, float w1,
int x2, int y2, float z2, float w2,
uint32_t color
) {
// We need to sort the vertices by y-coordinate ascending (y0 < y1 < y2)
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
float_swap(&z0, &z1);
float_swap(&w0, &w1);
}
if (y1 > y2) {
int_swap(&y1, &y2);
int_swap(&x1, &x2);
float_swap(&z1, &z2);
float_swap(&w1, &w2);
}
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
float_swap(&z0, &z1);
float_swap(&w0, &w1);
}
// Create vector points and texture coords after we sort the vertices
vec4_t point_a = { x0, y0, z0, w0 };
vec4_t point_b = { x1, y1, z1, w1 };
vec4_t point_c = { x2, y2, z2, w2 };
///////////////////////////////////////////////////////
// Render the upper part of the triangle (flat-bottom)
///////////////////////////////////////////////////////
float inv_slope_1 = 0;
float inv_slope_2 = 0;
if (y1 - y0 != 0) inv_slope_1 = (float)(x1 - x0) / abs(y1 - y0);
if (y2 - y0 != 0) inv_slope_2 = (float)(x2 - x0) / abs(y2 - y0);
if (y1 - y0 != 0) {
for (int y = y0; y <= y1; y++) {
int x_start = x1 + (y - y1) * inv_slope_1;
int x_end = x0 + (y - y0) * inv_slope_2;
if (x_end < x_start) {
int_swap(&x_start, &x_end); // swap if x_start is to the right of x_end
}
for (int x = x_start; x < x_end; x++) {
// Draw our pixel with the color that comes from the texture
draw_triangle_pixel(x, y, color, point_a, point_b, point_c);
}
}
}
///////////////////////////////////////////////////////
// Render the bottom part of the triangle (flat-top)
///////////////////////////////////////////////////////
inv_slope_1 = 0;
inv_slope_2 = 0;
if (y2 - y1 != 0) inv_slope_1 = (float)(x2 - x1) / abs(y2 - y1);
if (y2 - y0 != 0) inv_slope_2 = (float)(x2 - x0) / abs(y2 - y0);
if (y2 - y1 != 0) {
for (int y = y1; y <= y2; y++) {
int x_start = x1 + (y - y1) * inv_slope_1;
int x_end = x0 + (y - y0) * inv_slope_2;
if (x_end < x_start) {
int_swap(&x_start, &x_end); // swap if x_start is to the right of x_end
}
for (int x = x_start; x < x_end; x++) {
// Draw our pixel with the color that comes from the texture
draw_triangle_pixel(x, y, color, point_a, point_b, point_c);
}
}
}
}

View File

@ -23,8 +23,12 @@ typedef struct {
} triangle_t; } triangle_t;
void draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); void draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color);
void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); void draw_filled_triangle(
int x0, int y0, float z0, float w0,
int x1, int y1, float z1, float w1,
int x2, int y2, float z2, float w2,
uint32_t color
);
void draw_textured_triangle( void draw_textured_triangle(
int x0, int y0, float z0, float w0, float u0, float v0, int x0, int y0, float z0, float w0, float u0, float v0,
int x1, int y1, float z1, float w1, float u1, float v1, int x1, int y1, float z1, float w1, float u1, float v1,