aboutsummaryrefslogtreecommitdiff
path: root/src/renderer.cpp
diff options
context:
space:
mode:
authorvimene <vincent.menegaux@gmail.com>2023-12-09 06:33:39 +0100
committervimene <vincent.menegaux@gmail.com>2023-12-09 06:33:39 +0100
commitbf39fef7eed69e6d5ecfa272607cbf0fcc53b9a6 (patch)
tree81ac781a634f7618809d6322e1a2d8b544cbc798 /src/renderer.cpp
parent19c3e2b83c3c8b58576050b448f2f35d0687e717 (diff)
downloadengine-bf39fef7eed69e6d5ecfa272607cbf0fcc53b9a6.tar.gz
fixed perspective calculations
Diffstat (limited to 'src/renderer.cpp')
-rw-r--r--src/renderer.cpp116
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);
}
}
}