diff options
author | vimene <vincent.menegaux@gmail.com> | 2023-12-09 06:33:39 +0100 |
---|---|---|
committer | vimene <vincent.menegaux@gmail.com> | 2023-12-09 06:33:39 +0100 |
commit | bf39fef7eed69e6d5ecfa272607cbf0fcc53b9a6 (patch) | |
tree | 81ac781a634f7618809d6322e1a2d8b544cbc798 /src/renderer.cpp | |
parent | 19c3e2b83c3c8b58576050b448f2f35d0687e717 (diff) | |
download | engine-bf39fef7eed69e6d5ecfa272607cbf0fcc53b9a6.tar.gz |
fixed perspective calculations
Diffstat (limited to 'src/renderer.cpp')
-rw-r--r-- | src/renderer.cpp | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/src/renderer.cpp b/src/renderer.cpp index a946ce3..6e170f3 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -5,12 +5,14 @@ #include <memory> #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/vertex_data.h" using namespace engine; -Renderer::Renderer(std::unique_ptr<engine::fb::FrameBuffer> fb) : fb{std::move(fb)} { +Renderer::Renderer(std::unique_ptr<fb::FrameBuffer> fb) : fb{std::move(fb)} { depth_buf.resize(this->fb->width() * this->fb->height()); } @@ -33,33 +35,36 @@ void Renderer::clear() { fb->clear(); } -void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) { - std::array<engine::o3d::Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 }; +void Renderer::_draw_cropped_triangle(o3d::TriangleVertex4 root, o3d::TriangleDerivedVertex4 triangle) { + std::array<o3d::DerivedVertex4*, 3> sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 }; -#define SWAP_IF_LT(X,Y) ({\ - if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\ - engine::o3d::Vertex3* temp = sorted_vs[X];\ - sorted_vs[X] = sorted_vs[Y];\ - sorted_vs[Y] = temp;\ - }\ +#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 - engine::o3d::Vertex3 middle_vl = *sorted_vs[1]; - float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y); - engine::o3d::Vertex3 middle_vr{ + 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{ { sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x), sorted_vs[1]->point.y, - sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z) + 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)) }, - engine::o3d::VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac) + sorted_vs[0]->b0 + fac * (sorted_vs[2]->b0 - sorted_vs[0]->b0), + sorted_vs[0]->b1 + fac * (sorted_vs[2]->b1 - sorted_vs[0]->b1) }; if (middle_vr.point.x < middle_vl.point.x) { - engine::o3d::Vertex3 temp = middle_vr; + auto temp = middle_vr; middle_vr = middle_vl; middle_vl = temp; } @@ -72,6 +77,7 @@ void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) { for (int y = top_y; y <= bottom_y; y++) { float iy = static_cast<float>(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<int>(std::ceil(xl)); @@ -79,13 +85,23 @@ void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) { for (int x = left_x; x <= right_x; x++) { float ix = static_cast<float>(x); float t = (ix - xl) / (xr - xl); - // depth and vd don't take into account perspective - float u = s, v = t; - float depth = sorted_vs[0]->point.z + u * (middle_vl.point.z - sorted_vs[0]->point.z + v * (middle_vr.point.z - middle_vl.point.z)); - if (depth < depth_buf[x + y * fb->width()]) { - depth_buf[x + y * fb->width()] = depth; - fb->draw_point(x, y, engine::math::Vector3{static_cast<float>(face_ind) + .5f, 0.f, 0.f}, - engine::o3d::VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, u, v)); + 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; + math::Vector3 loc{ + sub_b0 * sorted_vs[0]->point.x + sub_b1 * middle_vl.point.x + (1.f - sub_b0 - sub_b1) * middle_vr.point.x, + sub_b0 * sorted_vs[0]->point.y + sub_b1 * middle_vl.point.y + (1.f - sub_b0 - sub_b1) * middle_vr.point.y, + sub_b0 * sorted_vs[0]->point.z + sub_b1 * middle_vl.point.z + (1.f - sub_b0 - sub_b1) * middle_vr.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, + sub_b0 * sorted_vs[0]->b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0, + sub_b0 * sorted_vs[0]->b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1)); } } } @@ -100,6 +116,7 @@ void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) { for (int y = top_y; y <= bottom_y; y++) { float iy = static_cast<float>(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<int>(std::ceil(xl)); @@ -107,13 +124,23 @@ void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) { for (int x = left_x; x <= right_x; x++) { float ix = static_cast<float>(x); float t = (ix - xl) / (xr - xl); - // depth and vd don't take into account perspective - float u = s, v = t; - float depth = sorted_vs[2]->point.z + u * (middle_vl.point.z - sorted_vs[2]->point.z + v * (middle_vr.point.z - middle_vl.point.z)); - if (depth < depth_buf[x + y * fb->width()]) { - depth_buf[x + y * fb->width()] = depth; - fb->draw_point(x, y, engine::math::Vector3{static_cast<float>(face_ind) + .5f, 0.f, 0.f}, - engine::o3d::VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, u, v)); + 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; + math::Vector3 loc{ + sub_b0 * sorted_vs[2]->point.x + sub_b1 * middle_vl.point.x + (1.f - sub_b0 - sub_b1) * middle_vr.point.x, + sub_b0 * sorted_vs[2]->point.y + sub_b1 * middle_vl.point.y + (1.f - sub_b0 - sub_b1) * middle_vr.point.y, + sub_b0 * sorted_vs[2]->point.z + sub_b1 * middle_vl.point.z + (1.f - sub_b0 - sub_b1) * middle_vr.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, + sub_b0 * sorted_vs[2]->b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0, + sub_b0 * sorted_vs[2]->b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1)); } } } @@ -121,25 +148,22 @@ void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) { } } -void Renderer::draw_triangle(engine::o3d::TriangleVertex4 triangle) { +void Renderer::draw_triangle(o3d::TriangleVertex4 triangle) { face_ind++; - for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) { - for (auto t2 : t1.div_by_w().crop_xy_out(-1.f, 1.f, -1.f, 1.f)) { - engine::math::Vector2 pp1 = t2.vertex1.point.xy(), - pp2 = t2.vertex2.point.xy(), - pp3 = t2.vertex3.point.xy(); + 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)) { + math::Vector2 pp1 = t2.derived_vertex1.point.xy(); + math::Vector2 pp2 = t2.derived_vertex2.point.xy(); + math::Vector2 pp3 = t2.derived_vertex3.point.xy(); if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue; - t2.vertex1.point = (t2.vertex1.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f; - t2.vertex2.point = (t2.vertex2.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f; - t2.vertex3.point = (t2.vertex3.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f; - float fw = static_cast<float>(fb->width()), fh = static_cast<float>(fb->height()); - t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f; - t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f; - t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f; - t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f; - t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f; - t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f; - _draw_cropped_triangle(t2); + float fw_over_2 = static_cast<float>(fb->width()) / 2.f, fh_over_2 = static_cast<float>(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; + _draw_cropped_triangle(triangle, t2); } } } |