2024-03-01 21:31:47 +08:00
|
|
|
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
|
|
|
// Author: tianlei.richard@qq.com (tianlei.richard)
|
|
|
|
|
2024-03-07 11:11:04 +08:00
|
|
|
#include <limits>
|
2024-03-08 11:54:37 +08:00
|
|
|
#include <thread>
|
2024-03-07 11:11:04 +08:00
|
|
|
|
2024-03-06 17:21:53 +08:00
|
|
|
#include "spdlog/spdlog.h"
|
2024-03-01 21:31:47 +08:00
|
|
|
|
2024-03-08 11:54:37 +08:00
|
|
|
#include "rasterizer.h"
|
|
|
|
|
2024-03-01 21:31:47 +08:00
|
|
|
Rasterizer::Rasterizer(const int width, const int height)
|
|
|
|
: width_(width), height_(height),
|
2024-03-05 21:43:08 +08:00
|
|
|
pixels_(std::vector<std::vector<PixelProperty>>(
|
2024-03-06 17:21:53 +08:00
|
|
|
height, std::vector<PixelProperty>(
|
|
|
|
width, PixelProperty{
|
|
|
|
0., 0., 0.,
|
|
|
|
-std::numeric_limits<double>::infinity()}))) {}
|
|
|
|
|
|
|
|
std::vector<std::vector<PixelProperty>>
|
|
|
|
Rasterizer::rasterize(const std::vector<Triangle> &primitives) {
|
|
|
|
for (const auto &t : primitives) {
|
2024-03-06 22:23:48 +08:00
|
|
|
const auto &triangle_points = t.get_points<3>();
|
|
|
|
|
2024-03-06 17:21:53 +08:00
|
|
|
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_);
|
2024-03-01 21:31:47 +08:00
|
|
|
|
2024-03-08 11:54:37 +08:00
|
|
|
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;
|
|
|
|
}
|
2024-03-06 17:21:53 +08:00
|
|
|
}
|
2024-03-05 21:43:08 +08:00
|
|
|
}
|
2024-03-08 11:54:37 +08:00
|
|
|
};
|
|
|
|
const int thread_num = 6;
|
|
|
|
std::vector<std::thread> 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();
|
2024-03-01 21:31:47 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 17:21:53 +08:00
|
|
|
return pixels_;
|
2024-03-01 21:31:47 +08:00
|
|
|
}
|
2024-03-05 21:43:08 +08:00
|
|
|
|
2024-03-08 11:54:37 +08:00
|
|
|
std::vector<std::vector<PixelProperty>> Rasterizer::get_picture() const {
|
|
|
|
return pixels_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Rasterizer::reset() {
|
|
|
|
pixels_ = std::vector<std::vector<PixelProperty>>(
|
|
|
|
height_,
|
|
|
|
std::vector<PixelProperty>(
|
|
|
|
width_,
|
|
|
|
PixelProperty{0., 0., 0., -std::numeric_limits<double>::infinity()}));
|
|
|
|
}
|
|
|
|
|
2024-03-05 21:43:08 +08:00
|
|
|
std::pair<bool, double> 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};
|
|
|
|
}
|