// Copyright 2024 Bytedance Inc. All Rights Reserved. // Author: tianlei.richard@qq.com (tianlei.richard) #include #include "spdlog/spdlog.h" #include "minus_renderer.h" #include "rasterizer.h" 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_); } float MinusRenderer::calculate_height(const float fov, const float near) { return std::fabs(near) * std::tan(fov * 0.5) * 2; } float MinusRenderer::calculate_width(const float height, const float ratio) { return height * ratio; } TransformMatrix MinusRenderer::squish_transform() { // 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; 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}, {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())); } } } 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 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 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(shading_points.size() - i - 1, j); if (std::isinf(std::fabs(row[j].depth))) { pixel_depth = 0; } else { const float k = static_cast(std::numeric_limits::max()) * 0.5; const float b = k; pixel_depth = static_cast(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()); }