// Copyright 2024 SquareBlock 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), shading_points_(std::vector>( height, std::vector(width, RasterizerResult{}))) {} void Rasterizer::rasterize(const int mesh_idx, const std::vector &primitives) { const int thread_num = 8; std::vector rasterize_threads; for (int begin = 0, offset = primitives.size() / thread_num, remainer = (primitives.size() % thread_num); begin < primitives.size();) { int end = begin + offset; if (remainer > 0) { end += 1; remainer -= 1; } rasterize_threads.push_back(std::thread( [this, mesh_idx](const std::vector &primitives, const int begin, const int end) { this->rasterize(mesh_idx, primitives, begin, end); }, primitives, begin, end)); begin = end; } for (auto &t : rasterize_threads) { t.join(); } } void Rasterizer::rasterize(const int mesh_idx, const std::vector &primitives, const int begin, const int end) { for (int t_id = begin; t_id < end; ++t_id) { const auto &t = primitives[t_id]; const auto &triangle_points = t.get_vertex_position(); 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_); for (int i = y_min; i < y_max; ++i) { for (int j = x_min; j <= x_max; ++j) { auto &property = shading_points_[i][j]; const auto &[is_inside, z_screen] = inside(Point2d{j + 0.5, i + 0.5}, t); if (is_inside && z_screen > property.depth) { property.depth = z_screen; property.triangle.mesh_index = mesh_idx; property.triangle.triangle_index = t_id; } } } } } const std::vector> & Rasterizer::get_shading_points() const { return shading_points_; } void Rasterizer::reset() { shading_points_ = std::vector>( height_, std::vector(width_, RasterizerResult{})); } std::pair Rasterizer::inside(const Point2d &p_screen, const Triangle &t) { const auto points = t.get_vertex_position(); const auto plane_normal = t.unit_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}; }