implemented perspective correct interpolation for textures
This commit is contained in:
20
src/main.c
20
src/main.c
@@ -131,8 +131,8 @@ void update(void){
|
|||||||
|
|
||||||
// Change the mesh scale/rotation values per animation frame
|
// Change the mesh scale/rotation values per animation frame
|
||||||
mesh.rotation.x += 0.01;
|
mesh.rotation.x += 0.01;
|
||||||
//mesh.rotation.y += 0.01;
|
mesh.rotation.y += 0.01;
|
||||||
//mesh.rotation.z += 0.01;
|
mesh.rotation.z += 0.01;
|
||||||
|
|
||||||
//mesh.scale.x += 0.01;
|
//mesh.scale.x += 0.01;
|
||||||
//mesh.scale.y += 0.01;
|
//mesh.scale.y += 0.01;
|
||||||
@@ -223,7 +223,7 @@ void update(void){
|
|||||||
projected_points[j].y *= (window_height / 2.0);
|
projected_points[j].y *= (window_height / 2.0);
|
||||||
|
|
||||||
// Invert the y values to account for flipped screen y coordinates
|
// Invert the y values to account for flipped screen y coordinates
|
||||||
//projected_points[j].y *= -1;
|
projected_points[j].y *= -1;
|
||||||
|
|
||||||
// translate the projected points to the middle of the screen
|
// translate the projected points to the middle of the screen
|
||||||
projected_points[j].x += (window_width / 2.0);
|
projected_points[j].x += (window_width / 2.0);
|
||||||
@@ -242,9 +242,9 @@ void update(void){
|
|||||||
|
|
||||||
triangle_t projected_triangle = {
|
triangle_t projected_triangle = {
|
||||||
.points = {
|
.points = {
|
||||||
{ projected_points[0].x, projected_points[0].y,},
|
{ projected_points[0].x, projected_points[0].y, projected_points[0].z, projected_points[0].w },
|
||||||
{ projected_points[1].x, projected_points[1].y },
|
{ projected_points[1].x, projected_points[1].y, projected_points[1].z, projected_points[1].w },
|
||||||
{ projected_points[2].x, projected_points[2].y },
|
{ projected_points[2].x, projected_points[2].y, projected_points[2].z, projected_points[2].w },
|
||||||
},
|
},
|
||||||
.texcoords = {
|
.texcoords = {
|
||||||
{ mesh_face.a_uv.u, mesh_face.a_uv.v },
|
{ mesh_face.a_uv.u, mesh_face.a_uv.v },
|
||||||
@@ -261,7 +261,7 @@ void update(void){
|
|||||||
array_push(triangles_to_render, projected_triangle);
|
array_push(triangles_to_render, projected_triangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort avg_depth of triangle faces for all z vertexs per triangle
|
// sort avg_depth of triangle faces for all z vertices per triangle
|
||||||
// painters algorithm
|
// painters algorithm
|
||||||
avg_depth_bubble_sort(triangles_to_render, array_length(triangles_to_render));
|
avg_depth_bubble_sort(triangles_to_render, array_length(triangles_to_render));
|
||||||
/*for (int t = 0; t < array_length(triangles_to_render); t++) {
|
/*for (int t = 0; t < array_length(triangles_to_render); t++) {
|
||||||
@@ -293,9 +293,9 @@ void render(void){
|
|||||||
// Draw textured triangle
|
// Draw textured triangle
|
||||||
if (render_method == RENDER_TEXTURED || render_method == RENDER_TEXTURED_WIRE) {
|
if (render_method == RENDER_TEXTURED || render_method == RENDER_TEXTURED_WIRE) {
|
||||||
draw_textured_triangle(
|
draw_textured_triangle(
|
||||||
triangle.points[0].x, triangle.points[0].y, triangle.texcoords[0].u, triangle.texcoords[0].v, // vertex A
|
triangle.points[0].x, triangle.points[0].y, triangle.points[0].z, triangle.points[0].w, triangle.texcoords[0].u, triangle.texcoords[0].v, // vertex A
|
||||||
triangle.points[1].x, triangle.points[1].y, triangle.texcoords[1].u, triangle.texcoords[1].v, // vertex B
|
triangle.points[1].x, triangle.points[1].y, triangle.points[1].z, triangle.points[1].w, triangle.texcoords[1].u, triangle.texcoords[1].v, // vertex B
|
||||||
triangle.points[2].x, triangle.points[2].y, triangle.texcoords[2].u, triangle.texcoords[2].v, // vertex C
|
triangle.points[2].x, triangle.points[2].y, triangle.points[2].z, triangle.points[2].w, triangle.texcoords[2].u, triangle.texcoords[2].v, // vertex C
|
||||||
mesh_texture
|
mesh_texture
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
24
src/mesh.c
24
src/mesh.c
@@ -25,23 +25,23 @@ vec3_t cube_vertices[N_CUBE_VERTICES] = {
|
|||||||
|
|
||||||
face_t cube_faces[N_CUBE_FACES] = {
|
face_t cube_faces[N_CUBE_FACES] = {
|
||||||
// front
|
// front
|
||||||
{ .a = 1, .b = 2, .c = 3, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
{ .a = 1, .b = 2, .c = 3, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
||||||
{ .a = 1, .b = 3, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
{ .a = 1, .b = 3, .c = 4, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
||||||
// right
|
// right
|
||||||
{ .a = 4, .b = 3, .c = 5, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
{ .a = 4, .b = 3, .c = 5, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
||||||
{ .a = 4, .b = 5, .c = 6, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
{ .a = 4, .b = 5, .c = 6, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
||||||
// back
|
// back
|
||||||
{ .a = 6, .b = 5, .c = 7, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
{ .a = 6, .b = 5, .c = 7, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
||||||
{ .a = 6, .b = 7, .c = 8, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
{ .a = 6, .b = 7, .c = 8, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
||||||
// left
|
// left
|
||||||
{ .a = 8, .b = 7, .c = 2, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
{ .a = 8, .b = 7, .c = 2, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
||||||
{ .a = 8, .b = 2, .c = 1, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
{ .a = 8, .b = 2, .c = 1, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
||||||
// top
|
// top
|
||||||
{ .a = 2, .b = 7, .c = 5, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
{ .a = 2, .b = 7, .c = 5, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
||||||
{ .a = 2, .b = 5, .c = 3, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
{ .a = 2, .b = 5, .c = 3, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
||||||
// bottom
|
// bottom
|
||||||
{ .a = 6, .b = 8, .c = 1, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF },
|
{ .a = 6, .b = 8, .c = 1, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF },
|
||||||
{ .a = 6, .b = 1, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }
|
{ .a = 6, .b = 1, .c = 4, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }
|
||||||
};
|
};
|
||||||
|
|
||||||
void load_cube_mesh_data(void) {
|
void load_cube_mesh_data(void) {
|
||||||
|
|||||||
@@ -122,26 +122,43 @@ vec3_t barycentric_weights(vec2_t a, vec2_t b, vec2_t c, vec2_t p) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void draw_texel(
|
void draw_texel(
|
||||||
int x, int y, color_t* texture,
|
int x, int y, color_t* texture,
|
||||||
vec2_t point_a, vec2_t point_b, vec2_t point_c,
|
vec4_t point_a, vec4_t point_b, vec4_t point_c,
|
||||||
float u0, float v0, float u1, float v1, float u2, float v2
|
tex2_t a_uv, tex2_t b_uv, tex2_t c_uv
|
||||||
) {
|
) {
|
||||||
vec2_t point_p = { x, y };
|
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);
|
||||||
|
|
||||||
vec3_t weights = barycentric_weights(point_a, point_b, point_c, point_p);
|
vec3_t weights = barycentric_weights(a, b, c, p);
|
||||||
|
|
||||||
float alpha = weights.x;
|
float alpha = weights.x;
|
||||||
float beta = weights.y;
|
float beta = weights.y;
|
||||||
float gamma = weights.z;
|
float gamma = weights.z;
|
||||||
|
|
||||||
// Perform the interpolation of all the U and V values using barycentric weights (coords)
|
// Variables to store the interpolated values of U, V, and also W for the current pixel
|
||||||
float interpolated_u = (u0 * alpha) + (u1 * beta) + (u2 * gamma);
|
float interpolated_u;
|
||||||
float interpolated_v = (v0 * alpha) + (v1 * beta) + (v2 * gamma);
|
float interpolated_v;
|
||||||
|
float interpolated_reciprocal_w;
|
||||||
|
|
||||||
|
// Perform the interpolation of all the U/w and V/w values using barycentric weights (coords) and a factor of 1/w (recpirocal)
|
||||||
|
interpolated_u = (a_uv.u / point_a.w) * alpha + (b_uv.u / point_b.w) * beta + (c_uv.u / point_c.w) * gamma;
|
||||||
|
interpolated_v = (a_uv.v / point_a.w) * alpha + (b_uv.v / point_b.w) * beta + (c_uv.v / point_c.w) * gamma;
|
||||||
|
|
||||||
|
// TODO: Could move outside of of function for performance increase, heavy to caclulate every pixel
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Divide back both interpolated values by 1/w
|
||||||
|
interpolated_u /= interpolated_reciprocal_w;
|
||||||
|
interpolated_v /= interpolated_reciprocal_w;
|
||||||
|
|
||||||
// Map the UV coordinate to the full texture width and height
|
// Map the UV coordinate to the full texture width and height
|
||||||
int tex_x = abs((int)(interpolated_u * texture_width));
|
int tex_x = abs((int)(interpolated_u * texture_width)) % texture_width;
|
||||||
int tex_y = abs((int)(interpolated_v * texture_height));
|
int tex_y = abs((int)(interpolated_v * texture_height)) % texture_height;
|
||||||
|
|
||||||
// TODO: figure out elegant way for stopping the values of tex_x and tex_y if outside bounds of array to prevent a buffer overflow in the texture[] array
|
// TODO: figure out elegant way for stopping the values of tex_x and tex_y if outside bounds of array to prevent a buffer overflow in the texture[] array
|
||||||
|
// perhaps modulo operator above? (interpolated_u * texture width) % texture_width to wrap coordinates to valid ranges (for height also)?
|
||||||
if ((texture_width * tex_y) + tex_x >= 0 && (texture_width * tex_y) + tex_x < (texture_width * texture_height)) {
|
if ((texture_width * tex_y) + tex_x >= 0 && (texture_width * tex_y) + tex_x < (texture_width * texture_height)) {
|
||||||
draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]);
|
draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]);
|
||||||
} else {
|
} else {
|
||||||
@@ -175,15 +192,17 @@ void draw_texel(
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// TODO: use color_t type or uint32_t type?
|
// TODO: use color_t type or uint32_t type?
|
||||||
void draw_textured_triangle(
|
void draw_textured_triangle(
|
||||||
int x0, int y0, float u0, float v0,
|
int x0, int y0, float z0, float w0, float u0, float v0,
|
||||||
int x1, int y1, float u1, float v1,
|
int x1, int y1, float z1, float w1, float u1, float v1,
|
||||||
int x2, int y2, float u2, float v2,
|
int x2, int y2, float z2, float w2, float u2, float v2,
|
||||||
color_t* texture
|
color_t* texture
|
||||||
) {
|
) {
|
||||||
// We need to sort the vertices by y-coordinate ascending (y0 < y1 < y2)
|
// We need to sort the vertices by y-coordinate ascending (y0 < y1 < y2)
|
||||||
if (y0 > y1) {
|
if (y0 > y1) {
|
||||||
int_swap(&y0, &y1);
|
int_swap(&y0, &y1);
|
||||||
int_swap(&x0, &x1);
|
int_swap(&x0, &x1);
|
||||||
|
float_swap(&z0, &z1);
|
||||||
|
float_swap(&w0, &w1);
|
||||||
float_swap(&u0, &u1);
|
float_swap(&u0, &u1);
|
||||||
float_swap(&v0, &v1);
|
float_swap(&v0, &v1);
|
||||||
}
|
}
|
||||||
@@ -191,6 +210,8 @@ void draw_textured_triangle(
|
|||||||
if (y1 > y2) {
|
if (y1 > y2) {
|
||||||
int_swap(&y1, &y2);
|
int_swap(&y1, &y2);
|
||||||
int_swap(&x1, &x2);
|
int_swap(&x1, &x2);
|
||||||
|
float_swap(&z1, &z2);
|
||||||
|
float_swap(&w1, &w2);
|
||||||
float_swap(&u1, &u2);
|
float_swap(&u1, &u2);
|
||||||
float_swap(&v1, &v2);
|
float_swap(&v1, &v2);
|
||||||
}
|
}
|
||||||
@@ -198,14 +219,19 @@ void draw_textured_triangle(
|
|||||||
if (y0 > y1) {
|
if (y0 > y1) {
|
||||||
int_swap(&y0, &y1);
|
int_swap(&y0, &y1);
|
||||||
int_swap(&x0, &x1);
|
int_swap(&x0, &x1);
|
||||||
|
float_swap(&z0, &z1);
|
||||||
|
float_swap(&w0, &w1);
|
||||||
float_swap(&u0, &u1);
|
float_swap(&u0, &u1);
|
||||||
float_swap(&v0, &v1);
|
float_swap(&v0, &v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create vector points after we sort the vertices
|
// Create vector points and texture coords after we sort the vertices
|
||||||
vec2_t point_a = { x0, y0 };
|
vec4_t point_a = { x0, y0, z0, w0 };
|
||||||
vec2_t point_b = { x1, y1 };
|
vec4_t point_b = { x1, y1, z1, w1 };
|
||||||
vec2_t point_c = { x2, y2 };
|
vec4_t point_c = { x2, y2, z2, w2 };
|
||||||
|
tex2_t a_uv = { u0, v0 };
|
||||||
|
tex2_t b_uv = { u1, v1 };
|
||||||
|
tex2_t c_uv = { u2, v2 };
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// Render the upper part of the triangle (flat-bottom)
|
// Render the upper part of the triangle (flat-bottom)
|
||||||
@@ -228,7 +254,7 @@ void draw_textured_triangle(
|
|||||||
|
|
||||||
for (int x = x_start; x < x_end; x++) {
|
for (int x = x_start; x < x_end; x++) {
|
||||||
// Draw our pixel with the color that comes from the texture
|
// Draw our pixel with the color that comes from the texture
|
||||||
draw_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2);
|
draw_texel(x, y, texture, point_a, point_b, point_c, a_uv, b_uv, c_uv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +281,7 @@ void draw_textured_triangle(
|
|||||||
|
|
||||||
for (int x = x_start; x < x_end; x++) {
|
for (int x = x_start; x < x_end; x++) {
|
||||||
// Draw our pixel with the color that comes from the texture
|
// Draw our pixel with the color that comes from the texture
|
||||||
draw_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2);
|
draw_texel(x, y, texture, point_a, point_b, point_c, a_uv, b_uv, c_uv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ typedef struct {
|
|||||||
} face_t;
|
} face_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec2_t points[3];
|
vec4_t points[3];
|
||||||
tex2_t texcoords[3];
|
tex2_t texcoords[3];
|
||||||
color_t color;
|
color_t color;
|
||||||
float avg_depth;
|
float avg_depth;
|
||||||
@@ -26,16 +26,16 @@ typedef struct {
|
|||||||
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, 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_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color);
|
||||||
void draw_textured_triangle(
|
void draw_textured_triangle(
|
||||||
int x0, int y0, float u0, float v0,
|
int x0, int y0, float z0, float w0, float u0, float v0,
|
||||||
int x1, int y1, float u1, float v1,
|
int x1, int y1, float z1, float w1, float u1, float v1,
|
||||||
int x2, int y2, float u2, float v2,
|
int x2, int y2, float z2, float w2, float u2, float v2,
|
||||||
color_t* texture
|
color_t* texture
|
||||||
);
|
);
|
||||||
|
|
||||||
void draw_texel(
|
void draw_texel(
|
||||||
int x, int y, color_t* texture,
|
int x, int y, color_t* texture,
|
||||||
vec2_t point_a, vec2_t point_b, vec2_t point_c,
|
vec4_t point_a, vec4_t point_b, vec4_t point_c,
|
||||||
float u0, float v0, float u1, float v1, float u2, float v2
|
tex2_t a_uv, tex2_t b_uv, tex2_t c_uv
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -168,6 +168,11 @@ vec3_t vec3_from_vec4(vec4_t v) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec2_t vec2_from_vec4(vec4_t v) {
|
||||||
|
vec2_t result = { v.x, v.y };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
vec3_t cube_vertice[8] = {
|
vec3_t cube_vertice[8] = {
|
||||||
|
|||||||
@@ -48,4 +48,6 @@ void vec3_normalize(vec3_t* v);
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
vec4_t vec4_from_vec3(vec3_t v);
|
vec4_t vec4_from_vec3(vec3_t v);
|
||||||
vec3_t vec3_from_vec4(vec4_t v);
|
vec3_t vec3_from_vec4(vec4_t v);
|
||||||
|
vec2_t vec2_from_vec4(vec4_t v);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user