From 6b765a85cf81bf4b7162e4c9280dd4054581c611 Mon Sep 17 00:00:00 2001 From: vimene Date: Mon, 11 Dec 2023 12:42:46 +0100 Subject: improved mesh definition - In the context of mesh definition, splited indices into vertex index, normal index and vertex data index to be able to specify different normals and vertex data for different faces using the same vertex --- src/renderer.cpp | 178 ++++++++++++++++++++++++------------------------------- 1 file changed, 78 insertions(+), 100 deletions(-) (limited to 'src/renderer.cpp') diff --git a/src/renderer.cpp b/src/renderer.cpp index 7a32807..1fa8799 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -6,8 +6,8 @@ #include "math/vector.h" #include "o3d/vertex.h" #include "o3d/deriv_vertex.h" -#include "o3d/tri_vertex.h" -#include "o3d/tri_deriv_vertex.h" +#include "o3d/tri.h" +#include "o3d/tri_deriv.h" #include "o3d/vertex_data.h" using namespace engine; @@ -34,127 +34,105 @@ void Renderer::clear() { fb->clear(); } -void Renderer::_draw_cropped_triangle(o3d::TriangleVertex4 root, o3d::TriangleDerivedVertex4 triangle) { - std::array sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 }; +enum TriangleSide { top, bottom }; -#define SWAP_IF_LT(X,Y) ({ \ - if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) { \ - auto temp = sorted_vs[X]; \ - sorted_vs[X] = sorted_vs[Y]; \ - sorted_vs[Y] = temp; \ - } \ - }) - SWAP_IF_LT(1, 0); - SWAP_IF_LT(2, 1); - SWAP_IF_LT(1, 0); -#undef SWAP_IF_LT +void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::TriangleDerived& triangle) { + std::array sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 }; + + { + const auto swap_if_lt = [&](auto x, auto y) { + if (sorted_vs[x]->vertex.y < sorted_vs[y]->vertex.y) { + auto temp = sorted_vs[x]; + sorted_vs[x] = sorted_vs[y]; + sorted_vs[y] = temp; + } + }; + + swap_if_lt(1, 0); + swap_if_lt(2, 1); + swap_if_lt(1, 0); + } auto middle_vl = *sorted_vs[1]; - const float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y); - const float fac_b0 = (1.f - fac) / sorted_vs[0]->point.w / ((1.f - fac) / sorted_vs[0]->point.w + fac / sorted_vs[2]->point.w); - o3d::DerivedVertex4 middle_vr{ + const float fac = (sorted_vs[1]->vertex.y - sorted_vs[0]->vertex.y) / (sorted_vs[2]->vertex.y - sorted_vs[0]->vertex.y); + const float fac_b0 = (1.f - fac) / sorted_vs[0]->vertex.w / ((1.f - fac) / sorted_vs[0]->vertex.w + fac / sorted_vs[2]->vertex.w); + o3d::DerivedVertex middle_vr{ { - sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x), - sorted_vs[1]->point.y, - fac_b0 * sorted_vs[0]->point.z + (1.f - fac_b0) * sorted_vs[2]->point.z, - 1.f / (1.f / sorted_vs[0]->point.w + fac * (1.f / sorted_vs[2]->point.w - 1.f / sorted_vs[0]->point.w)) + sorted_vs[0]->vertex.x + fac * (sorted_vs[2]->vertex.x - sorted_vs[0]->vertex.x), + sorted_vs[1]->vertex.y, + fac_b0 * sorted_vs[0]->vertex.z + (1.f - fac_b0) * sorted_vs[2]->vertex.z, + 1.f / (1.f / sorted_vs[0]->vertex.w + fac * (1.f / sorted_vs[2]->vertex.w - 1.f / sorted_vs[0]->vertex.w)) }, fac_b0 * sorted_vs[0]->b0 + (1.f - fac_b0) * sorted_vs[2]->b0, fac_b0 * sorted_vs[0]->b1 + (1.f - fac_b0) * sorted_vs[2]->b1 }; - if (middle_vr.point.x < middle_vl.point.x) { + if (middle_vr.vertex.x < middle_vl.vertex.x) { auto temp = middle_vr; middle_vr = middle_vl; middle_vl = temp; } - // top triangle - { - if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) { - int top_y = static_cast(std::floor(sorted_vs[0]->point.y + 1.f)); - int bottom_y = static_cast(std::ceil(sorted_vs[1]->point.y - 1.f)); - for (int y = top_y; y <= bottom_y; y++) { - float iy = static_cast(y); - float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y); - float sub_bb0 = 1.f - s; - float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x); - float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x); - int left_x = static_cast(std::ceil(xl)); - int right_x = static_cast(std::ceil(xr - 1.f)); - for (int x = left_x; x <= right_x; x++) { - float ix = static_cast(x); - float t = (ix - xl) / (xr - xl); - float sub_bb1 = s * (1.f - t); - float b_fac = 1.f / (sub_bb0 / sorted_vs[0]->point.w + sub_bb1 / middle_vl.point.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.point.w); - float sub_b0 = b_fac * sub_bb0 / sorted_vs[0]->point.w; - float sub_b1 = b_fac * sub_bb1 / middle_vl.point.w; - float b0 = sub_b0 * sorted_vs[0]->b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; - float b1 = sub_b0 * sorted_vs[0]->b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; - math::Vector3 loc{ - b0 * root.vertex1.point.x + b1 * root.vertex2.point.x + (1.f - b0 - b1) * root.vertex3.point.x, - b0 * root.vertex1.point.y + b1 * root.vertex2.point.y + (1.f - b0 - b1) * root.vertex3.point.y, - b0 * root.vertex1.point.z + b1 * root.vertex2.point.z + (1.f - b0 - b1) * root.vertex3.point.z - }; - if (loc.z < depth_buf[x + y * fb->width()]) { - depth_buf[x + y * fb->width()] = loc.z; - fb->draw_point(x, y, loc, o3d::VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1)); - } - } - } + const auto _draw_cropped_triangle_side = [&]() { + const int vertex_end_index = ([&]() { if constexpr (side == TriangleSide::top) return 0; else return 2; })(); + const o3d::DerivedVertex& vertex_end = *sorted_vs[vertex_end_index]; + if (vertex_end.vertex.y == sorted_vs[1]->vertex.y) + return; + int top_y; + int bottom_y; + if constexpr (side == TriangleSide::top) { + top_y = static_cast(std::floor(vertex_end.vertex.y + 1.f)); + bottom_y = static_cast(std::ceil(sorted_vs[1]->vertex.y - 1.f)); + } else { + bottom_y = static_cast(std::floor(vertex_end.vertex.y)); + top_y = static_cast(std::ceil(sorted_vs[1]->vertex.y)); } - } - - // bottom triangle - { - if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) { - int bottom_y = static_cast(std::floor(sorted_vs[2]->point.y)); - int top_y = static_cast(std::ceil(sorted_vs[1]->point.y)); - for (int y = top_y; y <= bottom_y; y++) { - float iy = static_cast(y); - float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y); - float sub_bb0 = 1.f - s; - float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x); - float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x); - int left_x = static_cast(std::ceil(xl)); - int right_x = static_cast(std::ceil(xr - 1.f)); - for (int x = left_x; x <= right_x; x++) { - float ix = static_cast(x); - float t = (ix - xl) / (xr - xl); - float sub_bb1 = s * (1.f - t); - float b_fac = 1.f / (sub_bb0 / sorted_vs[2]->point.w + sub_bb1 / middle_vl.point.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.point.w); - float sub_b0 = b_fac * sub_bb0 / sorted_vs[2]->point.w; - float sub_b1 = b_fac * sub_bb1 / middle_vl.point.w; - float b0 = sub_b0 * sorted_vs[2]->b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; - float b1 = sub_b0 * sorted_vs[2]->b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; - math::Vector3 loc{ - b0 * root.vertex1.point.x + b1 * root.vertex2.point.x + (1.f - b0 - b1) * root.vertex3.point.x, - b0 * root.vertex1.point.y + b1 * root.vertex2.point.y + (1.f - b0 - b1) * root.vertex3.point.y, - b0 * root.vertex1.point.z + b1 * root.vertex2.point.z + (1.f - b0 - b1) * root.vertex3.point.z - }; - if (loc.z < depth_buf[x + y * fb->width()]) { - depth_buf[x + y * fb->width()] = loc.z; - fb->draw_point(x, y, loc, o3d::VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1)); - } + for (int y = top_y; y <= bottom_y; y++) { + float iy = static_cast(y); + float s = (iy - vertex_end.vertex.y) / (sorted_vs[1]->vertex.y - vertex_end.vertex.y); + float sub_bb0 = 1.f - s; + float xl = vertex_end.vertex.x + s * (middle_vl.vertex.x - vertex_end.vertex.x); + float xr = vertex_end.vertex.x + s * (middle_vr.vertex.x - vertex_end.vertex.x); + int left_x = static_cast(std::ceil(xl)); + int right_x = static_cast(std::ceil(xr - 1.f)); + for (int x = left_x; x <= right_x; x++) { + float ix = static_cast(x); + float t = (ix - xl) / (xr - xl); + float sub_bb1 = s * (1.f - t); + float b_fac = 1.f / (sub_bb0 / vertex_end.vertex.w + sub_bb1 / middle_vl.vertex.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.vertex.w); + float sub_b0 = b_fac * sub_bb0 / vertex_end.vertex.w; + float sub_b1 = b_fac * sub_bb1 / middle_vl.vertex.w; + float b0 = sub_b0 * vertex_end.b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0; + float b1 = sub_b0 * vertex_end.b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1; + math::Vector3 loc{ + b0 * root.vertex1.vertex.x + b1 * root.vertex2.vertex.x + (1.f - b0 - b1) * root.vertex3.vertex.x, + b0 * root.vertex1.vertex.y + b1 * root.vertex2.vertex.y + (1.f - b0 - b1) * root.vertex3.vertex.y, + b0 * root.vertex1.vertex.z + b1 * root.vertex2.vertex.z + (1.f - b0 - b1) * root.vertex3.vertex.z + }; + if (loc.z < depth_buf[x + y * fb->width()]) { + depth_buf[x + y * fb->width()] = loc.z; + fb->draw_point(x, y, loc, o3d::VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1)); } } } - } + }; + _draw_cropped_triangle_side.operator()(); + _draw_cropped_triangle_side.operator()(); } -void Renderer::draw_triangle(o3d::TriangleVertex4 triangle) { +void Renderer::draw_triangle(o3d::Triangle triangle) { for (auto t1 : triangle.to_derived().crop_z_out(-1.f, 1.f)) { for (auto t2 : t1.div_by_w().perspective_crop_xy_out(-1.f, 1.f, -1.f, 1.f)) { - auto pp1 = t2.derived_vertex1.point.xy(); - auto pp2 = t2.derived_vertex2.point.xy(); - auto pp3 = t2.derived_vertex3.point.xy(); + auto pp1 = t2.derived_vertex1.vertex.xy(); + auto pp2 = t2.derived_vertex2.vertex.xy(); + auto pp3 = t2.derived_vertex3.vertex.xy(); if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue; float fw_over_2 = static_cast(fb->width()) / 2.f, fh_over_2 = static_cast(fb->height()) / 2.f; - t2.derived_vertex1.point.x = (t2.derived_vertex1.point.x + 1.f) * fw_over_2 - .5f; - t2.derived_vertex1.point.y = (t2.derived_vertex1.point.y + 1.f) * fh_over_2 - .5f; - t2.derived_vertex2.point.x = (t2.derived_vertex2.point.x + 1.f) * fw_over_2 - .5f; - t2.derived_vertex2.point.y = (t2.derived_vertex2.point.y + 1.f) * fh_over_2 - .5f; - t2.derived_vertex3.point.x = (t2.derived_vertex3.point.x + 1.f) * fw_over_2 - .5f; - t2.derived_vertex3.point.y = (t2.derived_vertex3.point.y + 1.f) * fh_over_2 - .5f; + t2.derived_vertex1.vertex.x = (t2.derived_vertex1.vertex.x + 1.f) * fw_over_2 - .5f; + t2.derived_vertex1.vertex.y = (t2.derived_vertex1.vertex.y + 1.f) * fh_over_2 - .5f; + t2.derived_vertex2.vertex.x = (t2.derived_vertex2.vertex.x + 1.f) * fw_over_2 - .5f; + t2.derived_vertex2.vertex.y = (t2.derived_vertex2.vertex.y + 1.f) * fh_over_2 - .5f; + t2.derived_vertex3.vertex.x = (t2.derived_vertex3.vertex.x + 1.f) * fw_over_2 - .5f; + t2.derived_vertex3.vertex.y = (t2.derived_vertex3.vertex.y + 1.f) * fh_over_2 - .5f; _draw_cropped_triangle(triangle, t2); } } -- cgit v1.2.3