diff --git a/src/common.h b/src/common.h index 43bfbfa..1b43053 100644 --- a/src/common.h +++ b/src/common.h @@ -12,3 +12,4 @@ using Point2d = Eigen::Vector2d; using Point3d = Eigen::Vector3d; using BBox = cv::Rect2i; using PixelProperty = Eigen::Vector4d; +using TransformMatrix = Eigen::Matrix; diff --git a/src/main.cc b/src/main.cc index 0092b60..7fde665 100644 --- a/src/main.cc +++ b/src/main.cc @@ -17,12 +17,12 @@ int main(int argc, char *argv[]) { const int resolution_height = 180; const int far = -1000; const int near = -10; - const float fov = 120. / 360. * M_PI; + const float fov = 120. / 180. * M_PI; const float aspect_ratio = static_cast(resolution_width) / static_cast(resolution_height); std::vector primitives{ - {Point3d{90, 45, -2}, Point3d{180, 135, -2}, Point3d{270, 45, -2}}}; + {Point3d{10, 5, -20}, Point3d{30, 25, -20}, Point3d{55, 5, -20}}}; cv::namedWindow("MinusRenderer", cv::WINDOW_AUTOSIZE); const auto start = std::chrono::steady_clock::now(); @@ -31,13 +31,16 @@ int main(int argc, char *argv[]) { const auto elapse = std::chrono::duration_cast( std::chrono::steady_clock::now() - start) .count(); - renderer.model_transform( - Eigen::AngleAxisd(0.125 * M_PI, Eigen::Vector3d::UnitY()) - .toRotationMatrix()); + TransformMatrix m{ + Eigen::Transform( + Eigen::AngleAxisd(0.125 * M_PI, Eigen::Vector3d::UnitZ()) + .toRotationMatrix()) + .matrix()}; + renderer.model_transform(m); const auto &color_image = renderer.render(resolution_width, resolution_height); cv::imshow("MinusRenderer", color_image); - } while (cv::waitKey(50) == -1); + } while (cv::waitKey(25) == -1); cv::destroyWindow("MinusRenderer"); return 0; diff --git a/src/minus_renderer.cc b/src/minus_renderer.cc index 1b92e93..5b4d3fc 100644 --- a/src/minus_renderer.cc +++ b/src/minus_renderer.cc @@ -1,27 +1,72 @@ // Copyright 2024 Bytedance Inc. All Rights Reserved. // Author: tianlei.richard@qq.com (tianlei.richard) +#include +#include + #include "minus_renderer.h" #include "rasterizer.h" + #include "spdlog/spdlog.h" -#include MinusRenderer::MinusRenderer(float near, float far, float fov, float aspect_ratio, std::vector &&primitives) : near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio), height_(calculate_height(fov, near)), - width_(calculate_width(height_, aspect_ratio)), primitives_(primitives) {} + width_(calculate_width(height_, aspect_ratio)), primitives_(primitives) { + spdlog::info("fov: {}, aspect ratio: {}, width: {}, height: {}", fov_, + aspect_ratio_, width_, height_); +} -int MinusRenderer::calculate_height(const float fov, const float near) { +float MinusRenderer::calculate_height(const float fov, const float near) { return std::fabs(near) * std::tan(fov * 0.5) * 2; } -int MinusRenderer::calculate_width(const float height, const float ratio) { +float MinusRenderer::calculate_width(const float height, const float ratio) { return height * ratio; } -void MinusRenderer::model_transform(const Triangle::AffineTransformType &m) { +TransformMatrix MinusRenderer::squish_tranform() { + // Frustum to Cuboid + return TransformMatrix{{near_, 0, 0, 0}, + {0, near_, 0, 0}, + {0, 0, near_ + far_, -near_ * far_}, + {0, 0, 1, 0}}; +} + +TransformMatrix MinusRenderer::orthographic_tranform() { + + const auto right = width_ * 0.5; + const auto left = -right; + const auto top = height_ * 0.5; + const auto bottom = -top; + spdlog::info("near: {}, far: {}, top: {}, bottom: {}, left: {}, right: {}", + near_, far_, top, bottom, left, right); + + TransformMatrix m{{1, 0, 0, -0.5 * (right - left)}, + {0, 1, 0, -0.5 * (top - bottom)}, + {0, 0, 1, -0.5 * (far_ - near_)}, + {0, 0, 0, 1}}; + + m = TransformMatrix{{2 / (right - left), 0, 0, 0}, + {0, 2 / (top - bottom), 0, 0}, + {0, 0, 2 / std::fabs(far_ - near_), 0}, + {0, 0, 0, 1}} * + m; + + std::cout << m << '\n'; + return m; +} + +TransformMatrix MinusRenderer::view_port_transform() { + return TransformMatrix{{width_ * 0.5, 0, 0, width_ * 0.5}, + {0, height_ * 0.5, 0, height_ * 0.5}, + {0, 0, 1, 0}, + {0, 0, 0, 1}}; +} + +void MinusRenderer::model_transform(const TransformMatrix &m) { for (auto &t : primitives_) { t.affine_transform(m); } @@ -29,8 +74,18 @@ void MinusRenderer::model_transform(const Triangle::AffineTransformType &m) { cv::Mat MinusRenderer::render(const int resolution_width, const int resolution_height) { + std::vector primitives; + for (const auto &t : primitives_) { + primitives.push_back(t); + } + for (auto &t : primitives) { + t.projective_transform(squish_tranform()); + t.affine_transform(orthographic_tranform()); + t.affine_transform(view_port_transform()); + } + Rasterizer rasterizer{resolution_width, resolution_height}; - const auto &pixels = rasterizer.rasterize(primitives_); + const auto &pixels = rasterizer.rasterize(primitives); assert(!pixels.empty()); cv::Mat color_image(pixels.size(), (pixels[0]).size(), CV_8UC3); diff --git a/src/minus_renderer.h b/src/minus_renderer.h index 313b2e7..50f1459 100644 --- a/src/minus_renderer.h +++ b/src/minus_renderer.h @@ -15,11 +15,16 @@ public: cv::Mat render(const int resolution_width, const int resolution_height); public: - void model_transform(const Triangle::AffineTransformType &m); + void model_transform(const TransformMatrix &m); private: - static int calculate_height(const float fov, const float near); - static int calculate_width(const float height, const float ratio); + static float calculate_height(const float fov, const float near); + static float calculate_width(const float height, const float ratio); + +private: + TransformMatrix squish_tranform(); + TransformMatrix orthographic_tranform(); + TransformMatrix view_port_transform(); private: float near_; @@ -27,8 +32,8 @@ private: float fov_; // In radian float aspect_ratio_; - int height_; - int width_; + float height_; + float width_; std::vector primitives_; }; diff --git a/src/rasterizer.cc b/src/rasterizer.cc index 6e29ef9..faaf7c3 100644 --- a/src/rasterizer.cc +++ b/src/rasterizer.cc @@ -4,6 +4,7 @@ #include "rasterizer.h" #include "spdlog/fmt/ostr.h" // github.com/gabime/spdlog/issues/1638 #include "spdlog/spdlog.h" +#include #include Rasterizer::Rasterizer(const int width, const int height) @@ -17,6 +18,10 @@ Rasterizer::Rasterizer(const int width, const int height) std::vector> Rasterizer::rasterize(const std::vector &primitives) { for (const auto &t : primitives) { + const auto &triangle_points = t.get_points<3>(); + std::cout << "triangle: " << triangle_points[0] << ", " + << triangle_points[1] << ", " << triangle_points[2] << '\n'; + const auto &aabb = t.axis_align_bbox(); const int x_min = std::min(std::max(0, aabb.x), width_); const int x_max = std::min(std::max(0, aabb.x + aabb.width), width_); diff --git a/src/triangle.cc b/src/triangle.cc index 2227d6c..988c416 100644 --- a/src/triangle.cc +++ b/src/triangle.cc @@ -2,7 +2,9 @@ // Author: tianlei.richard@qq.com (tianlei.richard) #include "triangle.h" +#include "spdlog/spdlog.h" #include +#include Triangle::Triangle(const Point3d &a, const Point3d &b, const Point3d &c) : points_({a, b, c}) {} @@ -26,15 +28,19 @@ Vector3d Triangle::normal_vector() const { return v1.cross(v2).normalized(); } -void Triangle::affine_transform(const AffineTransformType &m) { - Eigen::Transform affine_matrix(m); +void Triangle::affine_transform(const TransformMatrix &m) { for (auto &p : points_) { - p = (affine_matrix * Eigen::Vector4d(p.x(), p.y(), p.z(), 1)).head(3); + p = (m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1.)).head<3>(); } } -void Triangle::projective_transform(const ProjectiveTransformType &m) { +void Triangle::projective_transform(const TransformMatrix &m) { + // std::cout << "triangle: " << points_[0] << ", " << points_[1] << ", " + // << points_[2] << '\n'; for (auto &p : points_) { - p = (m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1)).head(3); + auto p_homo = m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1.); + // std::cout << "triangle: " << p_homo << '\n'; + // spdlog::info("w: {}", p_homo.w()); + p = (p_homo / p_homo.w()).head<3>(); } } diff --git a/src/triangle.h b/src/triangle.h index 2fd577c..4863dba 100644 --- a/src/triangle.h +++ b/src/triangle.h @@ -8,11 +8,6 @@ #include class Triangle { -public: - using AffineTransformType = Eigen::Matrix; - using ProjectiveTransformType = - Eigen::Transform; - private: using HomoPointType = Eigen::Vector4d; @@ -34,8 +29,8 @@ public: BBox axis_align_bbox() const; Vector3d normal_vector() const; - void affine_transform(const AffineTransformType &m); - void projective_transform(const ProjectiveTransformType &m); + void affine_transform(const TransformMatrix &m); + void projective_transform(const TransformMatrix &m); private: std::array points_;