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 | |
parent | 19c3e2b83c3c8b58576050b448f2f35d0687e717 (diff) | |
download | engine-bf39fef7eed69e6d5ecfa272607cbf0fcc53b9a6.tar.gz |
fixed perspective calculations
-rw-r--r-- | Makefile.am | 9 | ||||
-rw-r--r-- | src/fb/chfb.cpp | 8 | ||||
-rw-r--r-- | src/fb/pixfb.cpp | 7 | ||||
-rw-r--r-- | src/math/vector.cpp | 12 | ||||
-rw-r--r-- | src/math/vector.h | 4 | ||||
-rw-r--r-- | src/o3d/deriv_vertex.cpp | 11 | ||||
-rw-r--r-- | src/o3d/deriv_vertex.h | 19 | ||||
-rw-r--r-- | src/o3d/tri_deriv_vertex.cpp | 321 | ||||
-rw-r--r-- | src/o3d/tri_deriv_vertex.h | 24 | ||||
-rw-r--r-- | src/o3d/tri_vertex.cpp | 308 | ||||
-rw-r--r-- | src/o3d/tri_vertex.h | 17 | ||||
-rw-r--r-- | src/o3d/vertex.cpp | 4 | ||||
-rw-r--r-- | src/o3d/vertex.h | 1 | ||||
-rw-r--r-- | src/renderer.cpp | 116 | ||||
-rw-r--r-- | src/renderer.h | 8 |
15 files changed, 473 insertions, 396 deletions
diff --git a/Makefile.am b/Makefile.am index ecfea3a..91513f7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,10 +12,13 @@ engine_SOURCES = \ src/fb/fb.h src/fb/chfb.h src/fb/chfb.cpp src/fb/pixfb.h src/fb/pixfb.cpp \ src/math/vector.h src/math/vector.cpp \ src/math/mat4.h src/math/mat4.cpp \ - src/o3d/mesh.h src/o3d/mesh.cpp src/o3d/tri_vertex.h \ - src/o3d/obj3d.h src/o3d/obj3d.cpp src/o3d/tri_vertex.h \ - src/o3d/tri_vertex.cpp src/o3d/vertex.h src/o3d/vertex.cpp \ + src/o3d/mesh.h src/o3d/mesh.cpp \ + src/o3d/obj3d.h src/o3d/obj3d.cpp \ src/o3d/vertex_data.h src/o3d/vertex_data.cpp \ + src/o3d/vertex.h src/o3d/vertex.cpp \ + src/o3d/deriv_vertex.h src/o3d/deriv_vertex.cpp \ + src/o3d/tri_vertex.h src/o3d/tri_vertex.cpp \ + src/o3d/tri_deriv_vertex.h src/o3d/tri_deriv_vertex.cpp \ src/o3d/camera.h src/o3d/camera.cpp \ src/o3d/scene.h src/o3d/scene.cpp engine_CPPFLAGS = -Wall -Wextra $(DEPS_CPPFLAGS) diff --git a/src/fb/chfb.cpp b/src/fb/chfb.cpp index b5c0ae0..e3c0cf1 100644 --- a/src/fb/chfb.cpp +++ b/src/fb/chfb.cpp @@ -1,10 +1,6 @@ #include "fb/chfb.h" -#include <array> -#include <cmath> -#include <vector> +#include <algorithm> #include "math/vector.h" -#include "o3d/vertex.h" -#include "o3d/tri_vertex.h" #include "o3d/vertex_data.h" using namespace engine::fb; @@ -38,7 +34,7 @@ void CharacterFrameBuffer::clear() { void CharacterFrameBuffer::draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) { (void) vd; - chars_vector[x + y * w] = face_char(static_cast<int>(loc.x)); + chars_vector[x + y * w] = face_char(0); } char CharacterFrameBuffer::face_char(int face_ind) const { diff --git a/src/fb/pixfb.cpp b/src/fb/pixfb.cpp index 26bc8f2..54da87f 100644 --- a/src/fb/pixfb.cpp +++ b/src/fb/pixfb.cpp @@ -1,12 +1,7 @@ #include "fb/pixfb.h" -#include <array> -#include <cmath> -#include <vector> #include <cstdint> #include <algorithm> #include "math/vector.h" -#include "o3d/vertex.h" -#include "o3d/tri_vertex.h" #include "o3d/vertex_data.h" using namespace engine::fb; @@ -40,7 +35,7 @@ void PixelFrameBuffer::clear() { void PixelFrameBuffer::draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) { (void) vd; - pixels_vector[x + y * w] = face_color(static_cast<int>(loc.x)); + pixels_vector[x + y * w] = face_color(0); } uint32_t PixelFrameBuffer::face_color(int face_ind) const { diff --git a/src/math/vector.cpp b/src/math/vector.cpp index 36e813d..306fc3d 100644 --- a/src/math/vector.cpp +++ b/src/math/vector.cpp @@ -87,10 +87,6 @@ Vector3 Vector3::round() const { return { std::round(x), std::round(y), std::round(z) }; } -Vector2 Vector3::xy() const { - return { x, y }; -} - Vector3 Vector3::cross(Vector3 other) const { return { y * other.z - z * other.y, @@ -154,12 +150,16 @@ Vector4 Vector4::round() const { return { std::round(x), std::round(y), std::round(z), std::round(w) }; } +Vector2 Vector4::xy() const { + return { x, y }; +} + Vector3 Vector4::xyz() const { return { x, y, z }; } -Vector3 Vector4::div_by_w() const { - return xyz() / w; +Vector4 Vector4::div_by_w() const { + return {x / w, y / w, z / w, w}; } Vector4 engine::math::operator*(float n, Vector4 other) { diff --git a/src/math/vector.h b/src/math/vector.h index 8f7059a..82e1513 100644 --- a/src/math/vector.h +++ b/src/math/vector.h @@ -36,7 +36,6 @@ class Vector3 { Vector3 operator+(Vector3 other) const; Vector3 operator-(Vector3 other) const; Vector3 round() const; - Vector2 xy() const; Vector3 cross(Vector3 other) const; }; @@ -60,8 +59,9 @@ class Vector4 { Vector4 operator+(Vector4 other) const; Vector4 operator-(Vector4 other) const; Vector4 round() const; + Vector2 xy() const; Vector3 xyz() const; - Vector3 div_by_w() const; + Vector4 div_by_w() const; }; Vector4 operator*(float n, Vector4 other); diff --git a/src/o3d/deriv_vertex.cpp b/src/o3d/deriv_vertex.cpp new file mode 100644 index 0000000..dcb2bff --- /dev/null +++ b/src/o3d/deriv_vertex.cpp @@ -0,0 +1,11 @@ +#include "o3d/deriv_vertex.h" +#include "math/vector.h" + +using namespace engine::o3d; + +DerivedVertex4::DerivedVertex4(engine::math::Vector4 point, float b0, float b1) : point{point}, b0{b0}, b1{b1} { +} + +DerivedVertex4 DerivedVertex4::div_by_w() const { + return {point.div_by_w(), b0, b1}; +} diff --git a/src/o3d/deriv_vertex.h b/src/o3d/deriv_vertex.h new file mode 100644 index 0000000..8945696 --- /dev/null +++ b/src/o3d/deriv_vertex.h @@ -0,0 +1,19 @@ +#ifndef O3D_DERIV_VERTEX_H +#define O3D_DERIV_VERTEX_H + +#include "math/vector.h" + +namespace engine::o3d { + +class DerivedVertex4 { + public: + engine::math::Vector4 point; + float b0, b1; + + DerivedVertex4(engine::math::Vector4 point, float b0, float b1); + DerivedVertex4 div_by_w() const; +}; + +} + +#endif // O3D_DERIV_VERTEX_H diff --git a/src/o3d/tri_deriv_vertex.cpp b/src/o3d/tri_deriv_vertex.cpp new file mode 100644 index 0000000..3605b51 --- /dev/null +++ b/src/o3d/tri_deriv_vertex.cpp @@ -0,0 +1,321 @@ +#include "o3d/tri_deriv_vertex.h" +#include <vector> +#include "math/vector.h" +#include "o3d/deriv_vertex.h" + +using namespace engine::o3d; + +TriangleDerivedVertex4::TriangleDerivedVertex4(DerivedVertex4 derived_vertex1, DerivedVertex4 derived_vertex2, DerivedVertex4 derived_vertex3) + : derived_vertex1{derived_vertex1}, derived_vertex2{derived_vertex2}, derived_vertex3{derived_vertex3} { +} + +#define P1_OUT 1 +#define P2_OUT 2 +#define P3_OUT 4 +static void _perspective_crop_x(std::vector<TriangleDerivedVertex4>& tris, TriangleDerivedVertex4 t, int n, float x) { + switch (n) { + case 0: + tris.push_back(t); + break; + case P1_OUT: + case P2_OUT: + case P3_OUT: + case P2_OUT | P3_OUT: + case P1_OUT | P3_OUT: + case P1_OUT | P2_OUT: + { + DerivedVertex4* q1; + DerivedVertex4* q2; + DerivedVertex4* q3; + switch (n) { + case P1_OUT: + case P2_OUT | P3_OUT: + q1 = &t.derived_vertex1; + q2 = &t.derived_vertex2; + q3 = &t.derived_vertex3; + break; + case P2_OUT: + case P1_OUT | P3_OUT: + q1 = &t.derived_vertex2; + q2 = &t.derived_vertex1; + q3 = &t.derived_vertex3; + break; + case P3_OUT: + case P1_OUT | P2_OUT: + q1 = &t.derived_vertex3; + q2 = &t.derived_vertex2; + q3 = &t.derived_vertex1; + break; + } + engine::math::Vector4 dq2 = q1->point - q2->point; + float fac2 = (x - q2->point.x) / dq2.x; + float r2w = 1.f / (fac2 / q1->point.w + (1.f - fac2) / q2->point.w); + float fac2_b = r2w * fac2 / q1->point.w; + DerivedVertex4 r2{ + { + x, + q2->point.y + fac2 * dq2.y, + fac2_b * q1->point.z + (1.f - fac2_b) * q2->point.z, + r2w + }, + fac2_b * q1->b0 + (1.f - fac2_b) * q2->b0, + fac2_b * q1->b1 + (1.f - fac2_b) * q2->b1 + }; + engine::math::Vector4 dq3 = q1->point - q3->point; + float fac3 = (x - q3->point.x) / dq3.x; + float r3w = 1.f / (fac3 / q1->point.w + (1.f - fac3) / q3->point.w); + float fac3_b = r3w * fac3 / q1->point.w; + DerivedVertex4 r3{ + { + x, + q3->point.y + fac3 * dq3.y, + fac3_b * q1->point.z + (1.f - fac3_b) * q3->point.z, + r3w + }, + fac3_b * q1->b0 + (1.f - fac3_b) * q3->b0, + fac3_b * q1->b1 + (1.f - fac3_b) * q3->b1 + }; + switch (n) { + case P1_OUT: + tris.push_back({r3, *q2, *q3}); + tris.push_back({r3, r2, *q2}); + break; + case P2_OUT: + tris.push_back({r2, *q3, *q2}); + tris.push_back({r2, r3, *q3}); + break; + case P3_OUT: + tris.push_back({r2, *q3, *q2}); + tris.push_back({r2, r3, *q3}); + break; + case P2_OUT | P3_OUT: + tris.push_back({*q1, r2, r3}); + break; + case P1_OUT | P3_OUT: + tris.push_back({*q1, r3, r2}); + break; + case P1_OUT | P2_OUT: + tris.push_back({*q1, r3, r2}); + break; + } + } + break; + case P1_OUT | P2_OUT | P3_OUT: + break; + } +} + +static void _perspective_crop_y(std::vector<TriangleDerivedVertex4>& tris, TriangleDerivedVertex4 t, int n, float y) { + switch (n) { + case 0: + tris.push_back(t); + break; + case P1_OUT: + case P2_OUT: + case P3_OUT: + case P2_OUT | P3_OUT: + case P1_OUT | P3_OUT: + case P1_OUT | P2_OUT: + { + DerivedVertex4* q1; + DerivedVertex4* q2; + DerivedVertex4* q3; + switch (n) { + case P1_OUT: + case P2_OUT | P3_OUT: + q1 = &t.derived_vertex1; + q2 = &t.derived_vertex2; + q3 = &t.derived_vertex3; + break; + case P2_OUT: + case P1_OUT | P3_OUT: + q1 = &t.derived_vertex2; + q2 = &t.derived_vertex1; + q3 = &t.derived_vertex3; + break; + case P3_OUT: + case P1_OUT | P2_OUT: + q1 = &t.derived_vertex3; + q2 = &t.derived_vertex2; + q3 = &t.derived_vertex1; + break; + } + engine::math::Vector4 dq2 = q1->point - q2->point; + float fac2 = (y - q2->point.y) / dq2.y; + float r2w = 1.f / (fac2 / q1->point.w + (1.f - fac2) / q2->point.w); + float fac2_b = r2w * fac2 / q1->point.w; + DerivedVertex4 r2{ + { + q2->point.x + fac2 * dq2.x, + y, + fac2_b * q1->point.z + (1.f - fac2_b) * q2->point.z, + r2w + }, + fac2_b * q1->b0 + (1.f - fac2_b) * q2->b0, + fac2_b * q1->b1 + (1.f - fac2_b) * q2->b1 + }; + engine::math::Vector4 dq3 = q1->point - q3->point; + float fac3 = (y - q3->point.y) / dq3.y; + float r3w = 1.f / (fac3 / q1->point.w + (1.f - fac3) / q3->point.w); + float fac3_b = r3w * fac3 / q1->point.w; + DerivedVertex4 r3{ + { + q3->point.x + fac3 * dq3.x, + y, + fac3_b * q1->point.z + (1.f - fac3_b) * q3->point.z, + r3w + }, + fac3_b * q1->b0 + (1.f - fac3_b) * q3->b0, + fac3_b * q1->b1 + (1.f - fac3_b) * q3->b1 + }; + switch (n) { + case P1_OUT: + tris.push_back({r3, *q2, *q3}); + tris.push_back({r3, r2, *q2}); + break; + case P2_OUT: + tris.push_back({r2, *q3, *q2}); + tris.push_back({r2, r3, *q3}); + break; + case P3_OUT: + tris.push_back({r2, *q3, *q2}); + tris.push_back({r2, r3, *q3}); + break; + case P2_OUT | P3_OUT: + tris.push_back({*q1, r2, r3}); + break; + case P1_OUT | P3_OUT: + tris.push_back({*q1, r3, r2}); + break; + case P1_OUT | P2_OUT: + tris.push_back({*q1, r3, r2}); + break; + } + } + break; + case P1_OUT | P2_OUT | P3_OUT: + break; + } +} + +std::vector<TriangleDerivedVertex4> TriangleDerivedVertex4::perspective_crop_xy_out(float x1, float x2, float y1, float y2) const { + std::vector<TriangleDerivedVertex4> tris_final; + std::vector<TriangleDerivedVertex4> tris1; + _perspective_crop_x(tris1, *this, (derived_vertex1.point.x < x1) | ((derived_vertex2.point.x < x1) << 1) | ((derived_vertex3.point.x < x1) << 2), x1); + for (auto t1 : tris1) { + std::vector<TriangleDerivedVertex4> tris2; + _perspective_crop_x(tris2, t1, (t1.derived_vertex1.point.x > x2) | ((t1.derived_vertex2.point.x > x2) << 1) | ((t1.derived_vertex3.point.x > x2) << 2), x2); + for (auto t2 : tris2) { + std::vector<TriangleDerivedVertex4> tris3; + _perspective_crop_y(tris3, t2, (t2.derived_vertex1.point.y < y1) | ((t2.derived_vertex2.point.y < y1) << 1) | ((t2.derived_vertex3.point.y < y1) << 2), y1); + for (auto t3 : tris3) + _perspective_crop_y(tris_final, t3, (t3.derived_vertex1.point.y > y2) | ((t3.derived_vertex2.point.y > y2) << 1) | ((t3.derived_vertex3.point.y > y2) << 2), y2); + } + } + return tris_final; +} + +static void _crop_z(std::vector<TriangleDerivedVertex4>& tris, TriangleDerivedVertex4 t, int n, float z) { + switch (n) { + case 0: + tris.push_back(t); + break; + case P1_OUT: + case P2_OUT: + case P3_OUT: + case P2_OUT | P3_OUT: + case P1_OUT | P3_OUT: + case P1_OUT | P2_OUT: + { + DerivedVertex4* q1; + DerivedVertex4* q2; + DerivedVertex4* q3; + switch (n) { + case P1_OUT: + case P2_OUT | P3_OUT: + q1 = &t.derived_vertex1; + q2 = &t.derived_vertex2; + q3 = &t.derived_vertex3; + break; + case P2_OUT: + case P1_OUT | P3_OUT: + q1 = &t.derived_vertex2; + q2 = &t.derived_vertex1; + q3 = &t.derived_vertex3; + break; + case P3_OUT: + case P1_OUT | P2_OUT: + q1 = &t.derived_vertex3; + q2 = &t.derived_vertex2; + q3 = &t.derived_vertex1; + break; + } + engine::math::Vector4 dq2 = q1->point - q2->point; + float fac2 = (z - q2->point.z) / dq2.z; + DerivedVertex4 r2{ + { + q2->point.x + fac2 * dq2.x, + q2->point.y + fac2 * dq2.y, + z, + q2->point.w + fac2 * dq2.w + }, + fac2 * q1->b0 + (1.f - fac2) * q2->b0, + fac2 * q1->b1 + (1.f - fac2) * q2->b1 + }; + engine::math::Vector4 dq3 = q1->point - q3->point; + float fac3 = (z - q3->point.z) / dq3.z; + DerivedVertex4 r3{ + { + q3->point.x + fac3 * dq3.x, + q3->point.y + fac3 * dq3.y, + z, + q3->point.w + fac3 * dq3.w + }, + fac3 * q1->b0 + (1.f - fac3) * q3->b0, + fac3 * q1->b1 + (1.f - fac3) * q3->b1 + }; + switch (n) { + case P1_OUT: + tris.push_back({r3, *q2, *q3}); + tris.push_back({r3, r2, *q2}); + break; + case P2_OUT: + tris.push_back({r2, *q3, *q2}); + tris.push_back({r2, r3, *q3}); + break; + case P3_OUT: + tris.push_back({r2, *q3, *q2}); + tris.push_back({r2, r3, *q3}); + break; + case P2_OUT | P3_OUT: + tris.push_back({*q1, r2, r3}); + break; + case P1_OUT | P3_OUT: + tris.push_back({*q1, r3, r2}); + break; + case P1_OUT | P2_OUT: + tris.push_back({*q1, r3, r2}); + break; + } + } + break; + case P1_OUT | P2_OUT | P3_OUT: + break; + } +} + +std::vector<TriangleDerivedVertex4> TriangleDerivedVertex4::crop_z_out(float z1, float z2) const { + std::vector<TriangleDerivedVertex4> tris; + _crop_z(tris, *this, (derived_vertex1.point.z < z1) | ((derived_vertex2.point.z < z1) << 1) | ((derived_vertex3.point.z < z1) << 2), z1); + std::vector<TriangleDerivedVertex4> tris2; + for (auto t : tris) + _crop_z(tris2, t, (t.derived_vertex1.point.z > z2) | ((t.derived_vertex2.point.z > z2) << 1) | ((t.derived_vertex3.point.z > z2) << 2), z2); + return tris2; +} +#undef P1_OUT +#undef P2_OUT +#undef P3_OUT + +TriangleDerivedVertex4 TriangleDerivedVertex4::div_by_w() const { + return {derived_vertex1.div_by_w(), derived_vertex2.div_by_w(), derived_vertex3.div_by_w()}; +} diff --git a/src/o3d/tri_deriv_vertex.h b/src/o3d/tri_deriv_vertex.h new file mode 100644 index 0000000..41ed4dc --- /dev/null +++ b/src/o3d/tri_deriv_vertex.h @@ -0,0 +1,24 @@ +#ifndef O3D_TRI_DERIV_VERTEX_H +#define O3D_TRI_DERIV_VERTEX_H + +#include <vector> +#include "o3d/vertex.h" +#include "o3d/deriv_vertex.h" + +namespace engine::o3d { + +class TriangleDerivedVertex4 { + public: + DerivedVertex4 derived_vertex1; + DerivedVertex4 derived_vertex2; + DerivedVertex4 derived_vertex3; + + TriangleDerivedVertex4(DerivedVertex4 derived_vertex1, DerivedVertex4 derived_vertex2, DerivedVertex4 derived_vertex3); + std::vector<TriangleDerivedVertex4> perspective_crop_xy_out(float x1, float x2, float y1, float y2) const; + std::vector<TriangleDerivedVertex4> crop_z_out(float z1, float z2) const; + TriangleDerivedVertex4 div_by_w() const; +}; + +} + +#endif // O3D_TRI_DERIV_VERTEX_H diff --git a/src/o3d/tri_vertex.cpp b/src/o3d/tri_vertex.cpp index bda219a..08f5e7e 100644 --- a/src/o3d/tri_vertex.cpp +++ b/src/o3d/tri_vertex.cpp @@ -2,315 +2,15 @@ #include <vector> #include "math/vector.h" #include "o3d/vertex_data.h" +#include "o3d/deriv_vertex.h" #include "o3d/vertex.h" -#include "o3d/tri_vertex.h" +#include "o3d/tri_deriv_vertex.h" using namespace engine::o3d; -TriangleVertex3::TriangleVertex3(Vertex3 vertex1, Vertex3 vertex2, Vertex3 vertex3) : vertex1{vertex1}, vertex2{vertex2}, vertex3{vertex3} { -} - -#define P1_OUT 1 -#define P2_OUT 2 -#define P3_OUT 4 -static void _crop_x(std::vector<TriangleVertex3>& tris, TriangleVertex3 t, int n, float x) { - switch (n) { - case 0: - tris.push_back(t); - break; - case P1_OUT: - case P2_OUT: - case P3_OUT: - case P2_OUT | P3_OUT: - case P1_OUT | P3_OUT: - case P1_OUT | P2_OUT: - { - Vertex3* q1; - Vertex3* q2; - Vertex3* q3; - switch (n) { - case P1_OUT: - case P2_OUT | P3_OUT: - q1 = &t.vertex1; - q2 = &t.vertex2; - q3 = &t.vertex3; - break; - case P2_OUT: - case P1_OUT | P3_OUT: - q1 = &t.vertex2; - q2 = &t.vertex1; - q3 = &t.vertex3; - break; - case P3_OUT: - case P1_OUT | P2_OUT: - q1 = &t.vertex3; - q2 = &t.vertex2; - q3 = &t.vertex1; - break; - } - engine::math::Vector3 dq2 = q1->point - q2->point; - float fac2 = (x - q2->point.x) / dq2.x; - Vertex3 r2{ - { - x, - q2->point.y + fac2 * dq2.y, - q2->point.z + fac2 * dq2.z - }, - VertexData::lerp(q2->data, q1->data, fac2) - }; - engine::math::Vector3 dq3 = q1->point - q3->point; - float fac3 = (x - q3->point.x) / dq3.x; - Vertex3 r3{ - { - x, - q3->point.y + fac3 * dq3.y, - q3->point.z + fac3 * dq3.z - }, - VertexData::lerp(q3->data, q1->data, fac3) - }; - switch (n) { - case P1_OUT: - tris.push_back({r3, *q2, *q3}); - tris.push_back({r3, r2, *q2}); - break; - case P2_OUT: - tris.push_back({r2, *q3, *q2}); - tris.push_back({r2, r3, *q3}); - break; - case P3_OUT: - tris.push_back({r2, *q3, *q2}); - tris.push_back({r2, r3, *q3}); - break; - case P2_OUT | P3_OUT: - tris.push_back({*q1, r2, r3}); - break; - case P1_OUT | P3_OUT: - tris.push_back({*q1, r3, r2}); - break; - case P1_OUT | P2_OUT: - tris.push_back({*q1, r3, r2}); - break; - } - } - break; - case P1_OUT | P2_OUT | P3_OUT: - break; - } -} - -static void _crop_y(std::vector<TriangleVertex3>& tris, TriangleVertex3 t, int n, float y) { - switch (n) { - case 0: - tris.push_back(t); - break; - case P1_OUT: - case P2_OUT: - case P3_OUT: - case P2_OUT | P3_OUT: - case P1_OUT | P3_OUT: - case P1_OUT | P2_OUT: - { - Vertex3* q1; - Vertex3* q2; - Vertex3* q3; - switch (n) { - case P1_OUT: - case P2_OUT | P3_OUT: - q1 = &t.vertex1; - q2 = &t.vertex2; - q3 = &t.vertex3; - break; - case P2_OUT: - case P1_OUT | P3_OUT: - q1 = &t.vertex2; - q2 = &t.vertex1; - q3 = &t.vertex3; - break; - case P3_OUT: - case P1_OUT | P2_OUT: - q1 = &t.vertex3; - q2 = &t.vertex2; - q3 = &t.vertex1; - break; - } - engine::math::Vector3 dq2 = q1->point - q2->point; - float fac2 = (y - q2->point.y) / dq2.y; - Vertex3 r2{ - { - q2->point.x + fac2 * dq2.x, - y, - q2->point.z + fac2 * dq2.z - }, - VertexData::lerp(q2->data, q1->data, fac2) - }; - engine::math::Vector3 dq3 = q1->point - q3->point; - float fac3 = (y - q3->point.y) / dq3.y; - Vertex3 r3{ - { - q3->point.x + fac3 * dq3.x, - y, - q3->point.z + fac3 * dq3.z - }, - VertexData::lerp(q3->data, q1->data, fac3) - }; - switch (n) { - case P1_OUT: - tris.push_back({r3, *q2, *q3}); - tris.push_back({r3, r2, *q2}); - break; - case P2_OUT: - tris.push_back({r2, *q3, *q2}); - tris.push_back({r2, r3, *q3}); - break; - case P3_OUT: - tris.push_back({r2, *q3, *q2}); - tris.push_back({r2, r3, *q3}); - break; - case P2_OUT | P3_OUT: - tris.push_back({*q1, r2, r3}); - break; - case P1_OUT | P3_OUT: - tris.push_back({*q1, r3, r2}); - break; - case P1_OUT | P2_OUT: - tris.push_back({*q1, r3, r2}); - break; - } - } - break; - case P1_OUT | P2_OUT | P3_OUT: - break; - } -} - -std::vector<TriangleVertex3> TriangleVertex3::crop_xy_out(float x1, float x2, float y1, float y2) const { - std::vector<TriangleVertex3> tris_final; - std::vector<TriangleVertex3> tris1; - _crop_x(tris1, *this, (vertex1.point.x < x1) | ((vertex2.point.x < x1) << 1) | ((vertex3.point.x < x1) << 2), x1); - for (auto t1 : tris1) { - std::vector<TriangleVertex3> tris2; - _crop_x(tris2, t1, (t1.vertex1.point.x > x2) | ((t1.vertex2.point.x > x2) << 1) | ((t1.vertex3.point.x > x2) << 2), x2); - for (auto t2 : tris2) { - std::vector<TriangleVertex3> tris3; - _crop_y(tris3, t2, (t2.vertex1.point.y < y1) | ((t2.vertex2.point.y < y1) << 1) | ((t2.vertex3.point.y < y1) << 2), y1); - for (auto t3 : tris3) - _crop_y(tris_final, t3, (t3.vertex1.point.y > y2) | ((t3.vertex2.point.y > y2) << 1) | ((t3.vertex3.point.y > y2) << 2), y2); - } - } - return tris_final; -} -#undef P1_OUT -#undef P2_OUT -#undef P3_OUT - TriangleVertex4::TriangleVertex4(Vertex4 vertex1, Vertex4 vertex2, Vertex4 vertex3) : vertex1{vertex1}, vertex2{vertex2}, vertex3{vertex3} { } -TriangleVertex4::TriangleVertex4(TriangleVertex3 triangle) : vertex1{triangle.vertex1}, vertex2{triangle.vertex2}, vertex3{triangle.vertex3} { -} - -#define P1_OUT 1 -#define P2_OUT 2 -#define P3_OUT 4 -static void _crop_z(std::vector<TriangleVertex4>& tris, TriangleVertex4 t, int n, float z) { - switch (n) { - case 0: - tris.push_back(t); - break; - case P1_OUT: - case P2_OUT: - case P3_OUT: - case P2_OUT | P3_OUT: - case P1_OUT | P3_OUT: - case P1_OUT | P2_OUT: - { - Vertex4* q1; - Vertex4* q2; - Vertex4* q3; - switch (n) { - case P1_OUT: - case P2_OUT | P3_OUT: - q1 = &t.vertex1; - q2 = &t.vertex2; - q3 = &t.vertex3; - break; - case P2_OUT: - case P1_OUT | P3_OUT: - q1 = &t.vertex2; - q2 = &t.vertex1; - q3 = &t.vertex3; - break; - case P3_OUT: - case P1_OUT | P2_OUT: - q1 = &t.vertex3; - q2 = &t.vertex2; - q3 = &t.vertex1; - break; - } - engine::math::Vector4 dq2 = q1->point - q2->point; - float fac2 = (z - q2->point.z) / dq2.z; - Vertex4 r2{ - { - q2->point.x + fac2 * dq2.x, - q2->point.y + fac2 * dq2.y, - z, - q2->point.w + fac2 * dq2.w - }, - VertexData::lerp(q2->data, q1->data, fac2) - }; - engine::math::Vector4 dq3 = q1->point - q3->point; - float fac3 = (z - q3->point.z) / dq3.z; - Vertex4 r3{ - { - q3->point.x + fac3 * dq3.x, - q3->point.y + fac3 * dq3.y, - z, - q3->point.w + fac3 * dq3.w - }, - VertexData::lerp(q3->data, q1->data, fac3) - }; - switch (n) { - case P1_OUT: - tris.push_back({r3, *q2, *q3}); - tris.push_back({r3, r2, *q2}); - break; - case P2_OUT: - tris.push_back({r2, *q3, *q2}); - tris.push_back({r2, r3, *q3}); - break; - case P3_OUT: - tris.push_back({r2, *q3, *q2}); - tris.push_back({r2, r3, *q3}); - break; - case P2_OUT | P3_OUT: - tris.push_back({*q1, r2, r3}); - break; - case P1_OUT | P3_OUT: - tris.push_back({*q1, r3, r2}); - break; - case P1_OUT | P2_OUT: - tris.push_back({*q1, r3, r2}); - break; - } - } - break; - case P1_OUT | P2_OUT | P3_OUT: - break; - } -} - -std::vector<TriangleVertex4> TriangleVertex4::crop_z_out(float z1, float z2) const { - std::vector<TriangleVertex4> tris; - _crop_z(tris, *this, (vertex1.point.z < z1) | ((vertex2.point.z < z1) << 1) | ((vertex3.point.z < z1) << 2), z1); - std::vector<TriangleVertex4> tris2; - for (auto t : tris) - _crop_z(tris2, t, (t.vertex1.point.z > z2) | ((t.vertex2.point.z > z2) << 1) | ((t.vertex3.point.z > z2) << 2), z2); - return tris2; -} -#undef P1_OUT -#undef P2_OUT -#undef P3_OUT - -TriangleVertex3 TriangleVertex4::div_by_w() const { - return {vertex1.div_by_w(), vertex2.div_by_w(), vertex3.div_by_w()}; +TriangleDerivedVertex4 TriangleVertex4::to_derived() const { + return {{vertex1.point, 1.f, 0.f}, {vertex2.point, 0.f, 1.f}, {vertex3.point, 0.f, 0.f}}; } diff --git a/src/o3d/tri_vertex.h b/src/o3d/tri_vertex.h index 368a5e0..715f649 100644 --- a/src/o3d/tri_vertex.h +++ b/src/o3d/tri_vertex.h @@ -1,21 +1,12 @@ #ifndef O3D_TRI_VERTEX_H #define O3D_TRI_VERTEX_H -#include "o3d/vertex.h" #include <vector> +#include "o3d/vertex.h" +#include "o3d/tri_deriv_vertex.h" namespace engine::o3d { -class TriangleVertex3 { - public: - Vertex3 vertex1; - Vertex3 vertex2; - Vertex3 vertex3; - - TriangleVertex3(Vertex3 vertex1, Vertex3 vertex2, Vertex3 vertex3); - std::vector<TriangleVertex3> crop_xy_out(float x1, float x2, float y1, float y2) const; -}; - class TriangleVertex4 { public: Vertex4 vertex1; @@ -23,9 +14,7 @@ class TriangleVertex4 { Vertex4 vertex3; TriangleVertex4(Vertex4 vertex1, Vertex4 vertex2, Vertex4 vertex3); - TriangleVertex4(TriangleVertex3 triangle); - std::vector<TriangleVertex4> crop_z_out(float z1, float z2) const; - TriangleVertex3 div_by_w() const; + TriangleDerivedVertex4 to_derived() const; }; } diff --git a/src/o3d/vertex.cpp b/src/o3d/vertex.cpp index 641eef4..ec9c05f 100644 --- a/src/o3d/vertex.cpp +++ b/src/o3d/vertex.cpp @@ -12,7 +12,3 @@ Vertex4::Vertex4(engine::math::Vector4 point, VertexData data) : point{point}, d Vertex4::Vertex4(Vertex3 vertex) : point{vertex.point}, data{vertex.data} { } - -Vertex3 Vertex4::div_by_w() const { - return {point.div_by_w(), data}; -} diff --git a/src/o3d/vertex.h b/src/o3d/vertex.h index 022fdf7..b0dd195 100644 --- a/src/o3d/vertex.h +++ b/src/o3d/vertex.h @@ -21,7 +21,6 @@ class Vertex4 { Vertex4(engine::math::Vector4 point, VertexData data); Vertex4(Vertex3 vertex); - Vertex3 div_by_w() const; }; } 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); } } } diff --git a/src/renderer.h b/src/renderer.h index 211a6fc..a82ad56 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -9,20 +9,20 @@ namespace engine { class Renderer { public: - std::unique_ptr<engine::fb::FrameBuffer> fb; + std::unique_ptr<fb::FrameBuffer> fb; - Renderer(std::unique_ptr<engine::fb::FrameBuffer> fb); + Renderer(std::unique_ptr<fb::FrameBuffer> fb); void resize(unsigned int w, unsigned int h); unsigned int width() const; unsigned int height() const; void clear(); - void draw_triangle(engine::o3d::TriangleVertex4 triangle); + void draw_triangle(o3d::TriangleVertex4 triangle); private: std::vector<float> depth_buf; int face_ind; - void _draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle); + void _draw_cropped_triangle(o3d::TriangleVertex4 root, o3d::TriangleDerivedVertex4 triangle); }; } |