MinusculeRender/src/minus_renderer.cc

149 lines
5.2 KiB
C++
Raw Normal View History

2024-03-01 21:31:47 +08:00
// Copyright 2024 Bytedance Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)
2024-03-06 22:23:48 +08:00
#include <cmath>
#include "spdlog/spdlog.h"
#include "minus_renderer.h"
2024-03-01 21:31:47 +08:00
#include "rasterizer.h"
2024-03-01 16:00:08 +08:00
MinusRenderer::MinusRenderer(float near, float far, float fov,
float aspect_ratio)
: near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio),
projection_matrix_(orthographic_transform() * squish_transform()) {
spdlog::info("near: {}, far: {}, fov: {}, aspect ratio: {}", near_, far_,
fov_, aspect_ratio_);
2024-03-06 22:23:48 +08:00
}
2024-03-01 21:31:47 +08:00
2024-03-06 22:23:48 +08:00
float MinusRenderer::calculate_height(const float fov, const float near) {
return std::fabs(near) * std::tan(fov * 0.5) * 2;
}
2024-03-01 21:31:47 +08:00
2024-03-06 22:23:48 +08:00
float MinusRenderer::calculate_width(const float height, const float ratio) {
return height * ratio;
}
2024-03-01 16:00:08 +08:00
TransformMatrix MinusRenderer::squish_transform() {
2024-03-06 22:23:48 +08:00
// 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_transform() {
const float height = calculate_height(fov_, near_);
const float width = calculate_width(height, aspect_ratio_);
const float right = width * 0.5;
const float left = -right;
const float top = height * 0.5;
const float bottom = -top;
2024-03-06 22:23:48 +08:00
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;
return m;
}
TransformMatrix MinusRenderer::view_port_transform(const float width,
const float height) {
return TransformMatrix{{width * 0.5, 0, 0, width * 0.5},
{0, height * 0.5, 0, height * 0.5},
2024-03-06 22:23:48 +08:00
{0, 0, 1, 0},
{0, 0, 0, 1}};
}
Point3d MinusRenderer::calculate_barycentric_coordinate(const Triangle &t,
const Point2d &p) {
const auto &points = t.get_vertex_position();
const auto &A = (points[0]).head(2);
const auto &B = (points[1]).head(2);
const auto &C = (points[2]).head(2);
double alpha =
((p.x() - B.x()) * (C.y() - B.y()) + (p.y() - B.y()) * (C.x() - B.x())) /
(-(A.x() - B.x()) * (C.y() - B.y()) + (A.y() - B.y()) * (C.x() - B.x()));
double beta =
(-(p.x() - C.x()) * (A.y() - C.y()) + (p.y() - C.y()) * (A.x() - C.x())) /
(-(B.x() - C.x()) * (A.y() - C.y()) + (B.y() - C.y()) * (A.x() - C.x()));
double gamma = 1. - alpha - beta;
return Point3d{alpha, beta, gamma};
}
void MinusRenderer::model_transform(const TransformMatrix &mtx) {
for (auto &m : meshes_) {
for (auto &t : m.get_primitives()) {
t.set_points(apply_transform(mtx, t.get_vertex_position()));
}
}
}
2024-03-01 16:00:08 +08:00
void MinusRenderer::view_transform(const TransformMatrix &mtx) {
for (auto &m : meshes_) {
for (auto &t : m.get_primitives()) {
t.set_points(apply_transform(mtx, t.get_vertex_position()));
}
}
}
cv::Mat MinusRenderer::render(const int resolution_width,
const int resolution_height) {
std::vector<Mesh> meshes = meshes_;
Rasterizer rasterizer{resolution_width, resolution_height};
for (auto &m : meshes) {
auto &primitives = m.get_primitives();
for (int i = 0; i < primitives.size(); ++i) {
auto &t = primitives[i];
const auto &triangle_vertices = t.get_vertex_position();
auto tmp = apply_transform(projection_matrix_, triangle_vertices);
const auto &triangle_indices = t.get_vertex_index();
std::vector<Point3d> triangle_uv;
for (int j = 0; j < triangle_indices.size(); ++j) {
const auto &uv = m.get_texture_coordinate(triangle_indices[j]);
triangle_uv.push_back(Point3d{uv.x(), uv.y(), 1});
}
apply_transform(projection_matrix_, triangle_uv);
t.set_points(apply_transform(
view_port_transform(resolution_width, resolution_height), tmp));
}
rasterizer.rasterize(primitives);
}
const auto &shading_points = rasterizer.get_picture();
assert(!shading_points.empty());
cv::Mat depth_image(shading_points.size(), (shading_points[0]).size(),
CV_8UC1);
for (int i = 0; i < shading_points.size(); ++i) {
const auto &row = shading_points[i];
for (int j = 0; j < row.size(); ++j) {
auto &pixel_depth =
depth_image.at<unsigned char>(shading_points.size() - i - 1, j);
if (std::isinf(std::fabs(row[j].depth))) {
pixel_depth = 0;
} else {
const float k =
static_cast<float>(std::numeric_limits<unsigned char>::max()) * 0.5;
const float b = k;
pixel_depth = static_cast<unsigned char>(k * row[j].depth + b);
}
}
}
return depth_image;
}
void MinusRenderer::load_mesh(const std::string &file_path) {
meshes_ = Mesh::load_mesh(file_path);
spdlog::info("Mesh size: {}, the primitives size of the first mesh: {}",
meshes_.size(), meshes_.front().get_primitives().size());
2024-03-01 16:00:08 +08:00
}