filled triangles using z-buffer
This commit is contained in:
parent
95c015d719
commit
d01a33e27c
@ -208,9 +208,6 @@ void update(void) {
|
||||
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
|
||||
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 }
|
||||
},
|
||||
.color = triangle_color,
|
||||
.avg_depth = avg_depth
|
||||
};
|
||||
|
||||
// Save the projected triangle in the array of triangles to render
|
||||
@ -253,9 +249,9 @@ void render(void) {
|
||||
// Draw filled triangle
|
||||
if (render_method == RENDER_FILL_TRIANGLE || render_method == RENDER_FILL_TRIANGLE_WIRE) {
|
||||
draw_filled_triangle(
|
||||
triangle.points[0].x, triangle.points[0].y, // vertex A
|
||||
triangle.points[1].x, triangle.points[1].y, // vertex B
|
||||
triangle.points[2].x, triangle.points[2].y, // vertex C
|
||||
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, triangle.points[1].z, triangle.points[1].w, // vertex B
|
||||
triangle.points[2].x, triangle.points[2].y, triangle.points[2].z, triangle.points[2].w, // vertex C
|
||||
triangle.color
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,122 +2,6 @@
|
||||
#include "swap.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
|
||||
@ -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.
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,8 +23,12 @@ typedef struct {
|
||||
} triangle_t;
|
||||
|
||||
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(
|
||||
int x0, int y0, float z0, float w0, float u0, float v0,
|
||||
int x1, int y1, float z1, float w1, float u1, float v1,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user