// Copyright 2024 Bytedance Inc. All Rights Reserved. // Author: tianlei.richard@qq.com (tianlei.richard) #include #include #include "spdlog/spdlog.h" #include "rasterizer.h" Rasterizer::Rasterizer(const int width, const int height) : width_(width), height_(height), pixels_(std::vector>( height, std::vector( width, PixelProperty{ 0., 0., 0., -std::numeric_limits::infinity()}))) {} std::vector> Rasterizer::rasterize(const std::vector &primitives) { for (const auto &t : primitives) { const auto &triangle_points = t.get_points<3>(); 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_); const int y_min = std::min(std::max(0, aabb.y), height_); const int y_max = std::min(std::max(0, aabb.y + aabb.height), height_); auto partial_rasterize = [x_min, x_max, &t, this](const int start, const int end) { for (int i = start; i < end; ++i) { for (int j = x_min; j <= x_max; ++j) { auto &property = (this->pixels_)[i][j]; const auto &[is_inside, z_screen] = inside(Point2d{j + 0.5, i + 0.5}, t); if (is_inside && z_screen > property[3]) { property[0] = 0; property[1] = 1; property[2] = 0; property[3] = z_screen; } } } }; const int thread_num = 6; std::vector rasterize_threads; for (int start = y_min, offset = (y_max - y_min) / thread_num, remainer = (y_max - y_min) % thread_num; start < y_max;) { int end = start + offset; if (remainer > 0) { end += 1; remainer -= 1; } rasterize_threads.push_back(std::thread(partial_rasterize, start, end)); start = end; } for (auto &t : rasterize_threads) { t.join(); } } return pixels_; } std::vector> Rasterizer::get_picture() const { return pixels_; } void Rasterizer::reset() { pixels_ = std::vector>( height_, std::vector( width_, PixelProperty{0., 0., 0., -std::numeric_limits::infinity()})); } std::pair Rasterizer::inside(const Point2d &p_screen, const Triangle &t) { const auto points = t.get_points<3>(); const auto plane_normal = t.normal_vector(); const auto plane_point = points[0]; const auto z_screen = plane_point.z() - (plane_normal.x() * (p_screen.x() - plane_point.x()) + plane_normal.y() * (p_screen.y() - plane_point.y())) / plane_normal.z(); const Point3d p{p_screen.x(), p_screen.y(), z_screen}; const auto v1 = points[1] - points[0]; const auto v2 = points[2] - points[1]; const auto v3 = points[0] - points[2]; const auto c1 = v1.cross(p - points[0]).normalized(); const auto c2 = v2.cross(p - points[1]).normalized(); const auto c3 = v3.cross(p - points[2]).normalized(); const auto r1 = c1.dot(c2); const auto r2 = c1.dot(c3); const auto r3 = c2.dot(c3); return {r1 > 0 && r2 > 0 && r3 > 0, z_screen}; }