support texture mapping.

This commit is contained in:
tianlei.richard 2024-03-22 20:12:09 +08:00
parent 974848ad96
commit 18bb7e4cd7
21 changed files with 278 additions and 113 deletions

View File

@ -3,7 +3,7 @@ project(minus_renderer)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
find_package(OpenCV REQUIRED core) find_package(OpenCV REQUIRED core imgproc highgui)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

View File

@ -1,7 +1,14 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
PROJECT(renderer) PROJECT(renderer)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} CPP_FILES) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
file(GLOB_RECURSE CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR} *.cc)
add_executable(${CMAKE_PROJECT_NAME} ${CPP_FILES}) add_executable(${CMAKE_PROJECT_NAME} ${CPP_FILES})
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS}) target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS})

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include "camera.h" #include "camera.h"

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include "common.h" #include "common.h"

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once #pragma once

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include <opencv2/core/core.hpp> #include <opencv2/core/core.hpp>
@ -152,15 +152,15 @@ int main(int argc, char *argv[]) {
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Texture must be bound first // // Texture must be bound first
GLint swizzle[4] = { // GLint swizzle[4] = {
GL_RED, // Shader Red channel source = Texture Red // GL_RED, // Shader Red channel source = Texture Red
GL_RED, // Shader Green channel source = Texture Red // GL_RED, // Shader Green channel source = Texture Red
GL_RED, // Shader Blue channel source = Texture Red // GL_RED, // Shader Blue channel source = Texture Red
GL_ONE // Shader Alpha channel source = One // GL_ONE // Shader Alpha channel source = One
}; // };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle); // glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image.cols, image.rows, 0, GL_RED, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows, 0, GL_BGR,
GL_UNSIGNED_BYTE, image.data); GL_UNSIGNED_BYTE, image.data);
ImGui::Image(reinterpret_cast<void *>(static_cast<intptr_t>(texture)), ImGui::Image(reinterpret_cast<void *>(static_cast<intptr_t>(texture)),
ImVec2(image.cols, image.rows)); ImVec2(image.cols, image.rows));

View File

@ -1,2 +0,0 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)

View File

@ -1,4 +0,0 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once

View File

@ -1,10 +1,10 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include "mesh.h" #include "mesh.h"
#include "OBJ_Loader.h" #include "OBJ_Loader.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <filesystem>
#define OBJL_VEC2_TO_EIGEN_VECTOR(objl_v) \ #define OBJL_VEC2_TO_EIGEN_VECTOR(objl_v) \
Eigen::Vector2d { objl_v.X, objl_v.Y } Eigen::Vector2d { objl_v.X, objl_v.Y }
@ -12,8 +12,9 @@
Eigen::Vector3d { objl_v.X, objl_v.Y, objl_v.Z } Eigen::Vector3d { objl_v.X, objl_v.Y, objl_v.Z }
Mesh::Mesh(const std::vector<std::shared_ptr<Vertex>> &vertices, Mesh::Mesh(const std::vector<std::shared_ptr<Vertex>> &vertices,
const std::vector<Triangle> &primitives) const std::vector<Triangle> &primitives,
: vertices_(vertices), primitives_(primitives) {} const std::shared_ptr<PhoneMaterial> &phone_material)
: vertices_(vertices), primitives_(primitives), material_(phone_material) {}
Point2d Mesh::get_texture_coordinate(const unsigned int index) const { Point2d Mesh::get_texture_coordinate(const unsigned int index) const {
return (vertices_[index])->texture_coordinate; return (vertices_[index])->texture_coordinate;
@ -24,6 +25,9 @@ Point3d Mesh::get_normal_vector(const unsigned int index) const {
} }
std::vector<Mesh> Mesh::load_mesh(const std::string &file_path) { std::vector<Mesh> Mesh::load_mesh(const std::string &file_path) {
const auto &obj_path = std::filesystem::path(file_path);
const auto &material_directory = obj_path.parent_path();
objl::Loader loader{}; objl::Loader loader{};
assert(loader.LoadFile(file_path.c_str())); assert(loader.LoadFile(file_path.c_str()));
@ -32,20 +36,28 @@ std::vector<Mesh> Mesh::load_mesh(const std::string &file_path) {
spdlog::info("Current mesh has {} vertices.", mesh.Vertices.size()); spdlog::info("Current mesh has {} vertices.", mesh.Vertices.size());
std::vector<std::shared_ptr<Vertex>> vertices; std::vector<std::shared_ptr<Vertex>> vertices;
for (int i = 0; i < mesh.Vertices.size(); i++) { for (decltype(mesh.Vertices)::size_type i = 0; i < mesh.Vertices.size();
i++) {
vertices.push_back(std::make_shared<Vertex>( vertices.push_back(std::make_shared<Vertex>(
OBJL_VEC3_TO_EIGEN_VECTOR(mesh.Vertices[i].Position), OBJL_VEC3_TO_EIGEN_VECTOR(mesh.Vertices[i].Position),
OBJL_VEC3_TO_EIGEN_VECTOR(mesh.Vertices[i].Normal), OBJL_VEC3_TO_EIGEN_VECTOR(mesh.Vertices[i].Normal),
OBJL_VEC2_TO_EIGEN_VECTOR(mesh.Vertices[i].TextureCoordinate))); OBJL_VEC2_TO_EIGEN_VECTOR(mesh.Vertices[i].TextureCoordinate)));
} }
std::vector<Triangle> primitives; std::vector<Triangle> primitives;
for (int i = 0; i < mesh.Indices.size(); i += 3) { for (decltype(mesh.Indices)::size_type i = 0; i < mesh.Indices.size();
i += 3) {
primitives.push_back(Triangle(vertices, mesh.Indices[i], primitives.push_back(Triangle(vertices, mesh.Indices[i],
mesh.Indices[i + 1], mesh.Indices[i + 2])); mesh.Indices[i + 1], mesh.Indices[i + 2]));
} }
res.push_back(Mesh(vertices, primitives)); std::vector<std::filesystem::path> texture_path;
if (!mesh.MeshMaterial.map_Kd.empty()) {
texture_path.push_back(material_directory / mesh.MeshMaterial.map_Kd);
}
auto material =
std::shared_ptr<PhoneMaterial>(new PhoneMaterial(texture_path));
res.push_back(Mesh(vertices, primitives, material));
} }
return res; return res;
} }

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once #pragma once
@ -7,21 +7,32 @@
#include <memory> #include <memory>
#include "common.h" #include "common.h"
#include "phone_material.h"
#include "triangle.h" #include "triangle.h"
class Mesh { class Mesh {
public: public:
Mesh(const std::vector<std::shared_ptr<Vertex>> &vertices, Mesh(const std::vector<std::shared_ptr<Vertex>> &vertices,
const std::vector<Triangle> &primitives); const std::vector<Triangle> &primitives,
const std::shared_ptr<PhoneMaterial> &phone_material);
static std::vector<Mesh> load_mesh(const std::string &file_path); static std::vector<Mesh> load_mesh(const std::string &file_path);
public: public:
Point2d get_texture_coordinate(const unsigned int index) const; Point2d get_texture_coordinate(const unsigned int index) const;
Point3d get_normal_vector(const unsigned int index) const; Point3d get_normal_vector(const unsigned int index) const;
const std::vector<Triangle> &get_primitives() const { return primitives_; };
std::vector<Triangle> &get_primitives() { return primitives_; }; std::vector<Triangle> &get_primitives() { return primitives_; };
std::shared_ptr<PhoneMaterial> &get_material() { return material_; }
const std::shared_ptr<PhoneMaterial> &get_material() const {
return material_;
}
private: private:
std::vector<std::shared_ptr<Vertex>> vertices_; std::vector<std::shared_ptr<Vertex>> vertices_;
std::vector<Triangle> primitives_; std::vector<Triangle> primitives_;
std::shared_ptr<PhoneMaterial> material_;
}; };

View File

@ -1,9 +1,10 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include <cmath> #include <cmath>
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <opencv2/highgui/highgui.hpp>
#include "minus_renderer.h" #include "minus_renderer.h"
#include "rasterizer.h" #include "rasterizer.h"
@ -62,20 +63,21 @@ TransformMatrix MinusRenderer::view_port_transform(const float width,
{0, 0, 0, 1}}; {0, 0, 0, 1}};
} }
Point3d MinusRenderer::calculate_barycentric_coordinate(const Triangle &t, std::tuple<double, double, double>
const Point2d &p) { MinusRenderer::calculate_barycentric_coordinate(const Triangle &t,
const Point2d &p) {
const auto &points = t.get_vertex_position(); const auto &points = t.get_vertex_position();
const auto &A = (points[0]).head(2); const auto &A = (points[0]).head(2);
const auto &B = (points[1]).head(2); const auto &B = (points[1]).head(2);
const auto &C = (points[2]).head(2); const auto &C = (points[2]).head(2);
double alpha = double alpha =
((p.x() - B.x()) * (C.y() - B.y()) + (p.y() - B.y()) * (C.x() - B.x())) / (-(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())); (-(A.x() - B.x()) * (C.y() - B.y()) + (A.y() - B.y()) * (C.x() - B.x()));
double beta = double beta =
(-(p.x() - C.x()) * (A.y() - C.y()) + (p.y() - C.y()) * (A.x() - C.x())) / (-(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())); (-(B.x() - C.x()) * (A.y() - C.y()) + (B.y() - C.y()) * (A.x() - C.x()));
double gamma = 1. - alpha - beta; double gamma = 1. - alpha - beta;
return Point3d{alpha, beta, gamma}; return {alpha, beta, gamma};
} }
void MinusRenderer::model_transform(const TransformMatrix &mtx) { void MinusRenderer::model_transform(const TransformMatrix &mtx) {
@ -104,41 +106,56 @@ cv::Mat MinusRenderer::render(const int resolution_width,
auto &t = primitives[i]; auto &t = primitives[i];
const auto &triangle_vertices = t.get_vertex_position(); const auto &triangle_vertices = t.get_vertex_position();
auto tmp = apply_transform(projection_matrix_, triangle_vertices); 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( t.set_points(apply_transform(
view_port_transform(resolution_width, resolution_height), tmp)); view_port_transform(resolution_width, resolution_height), tmp));
} }
rasterizer.rasterize(primitives);
} }
const auto &shading_points = rasterizer.get_picture(); const auto &shading_points = rasterizer.rasterize(meshes);
assert(!shading_points.empty()); assert(!shading_points.empty());
cv::Mat depth_image(shading_points.size(), (shading_points[0]).size(), cv::Mat color_image(shading_points.size(), (shading_points[0]).size(),
CV_8UC1); CV_8UC3);
for (int y = 0; y < shading_points.size(); ++y) {
for (int x = 0; x < shading_points[y].size(); ++x) {
auto &pixel_color =
color_image.at<cv::Vec3b>(shading_points.size() - y - 1, x);
pixel_color = cv::Vec3b(0, 0, 0);
for (int i = 0; i < shading_points.size(); ++i) { const auto &p = shading_points[y][x];
const auto &row = shading_points[i]; if (p.triangle.mesh_index >= 0 && p.triangle.mesh_index < meshes.size()) {
for (int j = 0; j < row.size(); ++j) { const auto &mesh = meshes[p.triangle.mesh_index];
auto &pixel_depth = const auto &primitives = mesh.get_primitives();
depth_image.at<unsigned char>(shading_points.size() - i - 1, j); if (p.triangle.triangle_index >= 0 &&
if (std::isinf(std::fabs(row[j].depth))) { p.triangle.triangle_index < primitives.size()) {
pixel_depth = 0; const auto &triangle = primitives[p.triangle.triangle_index];
} else { const auto &[alpha, beta, gamma] = calculate_barycentric_coordinate(
const float k = triangle, Point2d{x + 0.5, y + 0.5});
static_cast<float>(std::numeric_limits<unsigned char>::max()) * 0.5;
const float b = k; const auto &triangle_indices = triangle.get_vertex_index();
pixel_depth = static_cast<unsigned char>(k * row[j].depth + b); std::vector<Point3d> triangle_uv;
for (int j = 0; j < triangle_indices.size(); ++j) {
const auto &uv = mesh.get_texture_coordinate(triangle_indices[j]);
triangle_uv.push_back(Point3d{uv.x(), uv.y(), 1});
}
auto projective_uv = apply_transform(projection_matrix_, triangle_uv);
// TODO(tianlei): 推导一下为什么需要除以下面这个
auto w_reciprocal = alpha * (projective_uv[0].z()) +
beta * (projective_uv[1].z()) +
gamma * (2 * projective_uv[2].z());
Point2d pixel_uv{
(alpha * projective_uv[0].x() + beta * projective_uv[1].x() +
gamma * projective_uv[2].x()) /
w_reciprocal,
(alpha * projective_uv[0].y() + beta * projective_uv[1].y() +
gamma * projective_uv[2].y()) /
w_reciprocal};
auto &material = mesh.get_material();
pixel_color = material->sample_texture(0, pixel_uv);
}
} }
} }
} }
return depth_image; return color_image;
} }
void MinusRenderer::load_mesh(const std::string &file_path) { void MinusRenderer::load_mesh(const std::string &file_path) {

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once #pragma once
@ -24,8 +24,8 @@ private:
static float calculate_width(const float height, const float ratio); static float calculate_width(const float height, const float ratio);
static TransformMatrix view_port_transform(const float width, static TransformMatrix view_port_transform(const float width,
const float height); const float height);
static Point3d calculate_barycentric_coordinate(const Triangle &t, static std::tuple<double, double, double>
const Point2d &p); calculate_barycentric_coordinate(const Triangle &t, const Point2d &p);
private: private:
TransformMatrix squish_transform(); TransformMatrix squish_transform();

49
src/phone_material.cc Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)
#include "phone_material.h"
#include "spdlog/spdlog.h"
#include "util/interpolation.h"
#include <opencv2/highgui/highgui.hpp>
PhoneMaterial::PhoneMaterial(
const std::vector<std::filesystem::path> &texture_path) {
for (const auto &path : texture_path) {
if (!std::filesystem::exists(path)) {
spdlog::warn("Texture {} is not existed!", path.c_str());
continue;
}
const auto &img(cv::imread(path));
spdlog::debug("Texture at {}, shape: ({},{})", path.c_str(), img.cols,
img.rows);
textures_.push_back(img);
}
}
cv::Vec3b PhoneMaterial::sample_texture(const TextureId texture_id,
const Point2d &texture_coordinate) {
cv::Vec3b res{0, 0, 0};
if (texture_id >= 0 && texture_id < textures_.size()) {
const auto &texture = textures_[texture_id];
const double x = texture_coordinate.x() * texture.cols - 0.5;
const double y = texture_coordinate.y() * texture.rows - 0.5;
const int x_f = x;
const int x_c = x + 1.;
const float t_x = x - x_f;
const int y_f = y;
const int y_c = y + 1.;
const float t_y = y - y_f;
const cv::Vec3b &a = texture.at<cv::Vec3b>(x_f, y_f);
const cv::Vec3b &b = texture.at<cv::Vec3b>(x_f, y_c);
const cv::Vec3b &c = texture.at<cv::Vec3b>(x_c, y_f);
const cv::Vec3b &d = texture.at<cv::Vec3b>(x_c, y_c);
res = bilerp(t_x, t_y, a, b, c, d);
} else {
spdlog::warn("Sample texture {} at ({}, {}) failed!", texture_id,
texture_coordinate.x(), texture_coordinate.y());
}
return res;
}

27
src/phone_material.h Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once
#include <filesystem>
#include <opencv2/core/core.hpp>
#include <vector>
#include "common.h"
// Bling-Phone Matrerial
class PhoneMaterial {
public:
using TextureId = uint32_t;
PhoneMaterial(const std::vector<std::filesystem::path> &texture_path);
public:
cv::Vec3b sample_texture(const TextureId texture_id,
const Point2d &texture_coordinate);
private:
std::vector<cv::Mat> textures_;
uint32_t illumination_intensity_;
};

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include <limits> #include <limits>
@ -14,53 +14,61 @@ Rasterizer::Rasterizer(const int width, const int height)
height, std::vector<RasterizerResult>(width, RasterizerResult{}))) {} height, std::vector<RasterizerResult>(width, RasterizerResult{}))) {}
std::vector<std::vector<RasterizerResult>> std::vector<std::vector<RasterizerResult>>
Rasterizer::rasterize(const std::vector<Triangle> &primitives) { Rasterizer::rasterize(const std::vector<Mesh> &meshes) {
auto partial_rasterize = [&primitives, this](const int begin, const int end) { for (int m_id = 0; m_id < meshes.size(); ++m_id) {
for (int idx = begin; idx < end; ++idx) { const auto &primitives = (meshes[m_id]).get_primitives();
const auto &t = primitives[idx];
const auto &triangle_points = t.get_vertex_position();
const auto &aabb = t.axis_align_bbox(); const int thread_num = 8;
const int x_min = std::min(std::max(0, aabb.x), width_); std::vector<std::thread> rasterize_threads;
const int x_max = std::min(std::max(0, aabb.x + aabb.width), width_); for (int begin = 0, offset = primitives.size() / thread_num,
const int y_min = std::min(std::max(0, aabb.y), height_); remainer = (primitives.size() % thread_num);
const int y_max = std::min(std::max(0, aabb.y + aabb.height), height_); begin < primitives.size();) {
int end = begin + offset;
for (int i = y_min; i < y_max; ++i) { if (remainer > 0) {
for (int j = x_min; j <= x_max; ++j) { end += 1;
auto &property = (this->shading_points_)[i][j]; remainer -= 1;
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_index = idx;
}
}
} }
rasterize_threads.push_back(std::thread(
[this, m_id](const std::vector<Triangle> &primitives, const int begin,
const int end) {
this->rasterize(m_id, primitives, begin, end);
},
(meshes[m_id]).get_primitives(), begin, end));
begin = end;
} }
}; for (auto &t : rasterize_threads) {
t.join();
const int thread_num = 6;
std::vector<std::thread> 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(partial_rasterize, begin, end));
begin = end;
}
for (auto &t : rasterize_threads) {
t.join();
} }
return shading_points_; return shading_points_;
} }
std::vector<std::vector<RasterizerResult>> Rasterizer::get_picture() const { void Rasterizer::rasterize(const int mesh_idx,
return shading_points_; const std::vector<Triangle> &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;
}
}
}
}
} }
void Rasterizer::reset() { void Rasterizer::reset() {

View File

@ -1,15 +1,19 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once #pragma once
#include "mesh.h"
#include "triangle.h" #include "triangle.h"
#include <opencv2/core/core.hpp> #include <opencv2/core/core.hpp>
#include <vector> #include <vector>
typedef struct RasterizerResult { typedef struct RasterizerResult {
double depth{-std::numeric_limits<double>::infinity()}; double depth{-std::numeric_limits<double>::infinity()};
int64_t triangle_index{-1}; struct {
int32_t mesh_index{-1};
int64_t triangle_index{-1};
} triangle;
} RasterizerResult; } RasterizerResult;
class Rasterizer { class Rasterizer {
@ -18,15 +22,18 @@ public:
public: public:
std::vector<std::vector<RasterizerResult>> std::vector<std::vector<RasterizerResult>>
rasterize(const std::vector<Triangle> &primitives); rasterize(const std::vector<Mesh> &meshes);
std::vector<std::vector<RasterizerResult>> get_picture() const;
void reset(); void reset();
private: private:
static std::pair<bool, double> inside(const Point2d &p_screen, static std::pair<bool, double> inside(const Point2d &p_screen,
const Triangle &t); const Triangle &t);
private:
void rasterize(const int mesh_idx, const std::vector<Triangle> &primitives,
const int begin, const int end);
private: private:
int width_; int width_;
int height_; int height_;

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include "triangle.h" #include "triangle.h"

View File

@ -1,4 +1,4 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once #pragma once

10
src/util/interpolation.cc Normal file
View File

@ -0,0 +1,10 @@
// Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)
#include "interpolation.h"
template <>
cv::Vec3b lerp(const float t, const cv::Vec3b &a, const cv::Vec3b &b) {
return cv::Vec3b{lerp(t, a[0], b[0]), lerp(t, a[1], b[1]),
lerp(t, a[2], b[2])};
}

23
src/util/interpolation.h Normal file
View File

@ -0,0 +1,23 @@
// Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)
#pragma once
#include <opencv2/core/core.hpp>
template <typename T> T lerp(const float t, const T &a, const T &b) {
return t * static_cast<float>(b) + (1 - t) * static_cast<float>(a);
}
template <typename T>
T bilerp(const float t_h, const float t_v, const T &a, const T &b, const T &c,
const T &d) {
return lerp(t_v, lerp(t_h, a, b), lerp(t_h, c, d));
}
template <>
cv::Vec3b lerp(const float t, const cv::Vec3b &a, const cv::Vec3b &b);
// template <>
// cv::Vec3b bilerp(const float t_h, const float t_v, const cv::Vec3b &a,
// const cv::Vec3b &b, const cv::Vec3b &c, const cv::Vec3b &d);

View File

@ -1,5 +1,5 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@bytedance.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include "common.h" #include "common.h"
#include <cmath> #include <cmath>