support texture mapping.
This commit is contained in:
parent
974848ad96
commit
18bb7e4cd7
|
@ -3,7 +3,7 @@ project(minus_renderer)
|
|||
|
||||
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)
|
||||
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
cmake_minimum_required(VERSION 3.14)
|
||||
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})
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS})
|
||||
|
|
|
@ -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)
|
||||
|
||||
#include "camera.h"
|
||||
|
|
|
@ -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)
|
||||
|
||||
#include "common.h"
|
||||
|
|
|
@ -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)
|
||||
|
||||
#pragma once
|
||||
|
|
20
src/main.cc
20
src/main.cc
|
@ -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)
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
@ -152,15 +152,15 @@ int main(int argc, char *argv[]) {
|
|||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// Texture must be bound first
|
||||
GLint swizzle[4] = {
|
||||
GL_RED, // Shader Red channel source = Texture Red
|
||||
GL_RED, // Shader Green channel source = Texture Red
|
||||
GL_RED, // Shader Blue channel source = Texture Red
|
||||
GL_ONE // Shader Alpha channel source = One
|
||||
};
|
||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image.cols, image.rows, 0, GL_RED,
|
||||
// // Texture must be bound first
|
||||
// GLint swizzle[4] = {
|
||||
// GL_RED, // Shader Red channel source = Texture Red
|
||||
// GL_RED, // Shader Green channel source = Texture Red
|
||||
// GL_RED, // Shader Blue channel source = Texture Red
|
||||
// GL_ONE // Shader Alpha channel source = One
|
||||
// };
|
||||
// glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.cols, image.rows, 0, GL_BGR,
|
||||
GL_UNSIGNED_BYTE, image.data);
|
||||
ImGui::Image(reinterpret_cast<void *>(static_cast<intptr_t>(texture)),
|
||||
ImVec2(image.cols, image.rows));
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
|
@ -1,4 +0,0 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
||||
|
||||
#pragma once
|
28
src/mesh.cc
28
src/mesh.cc
|
@ -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)
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
#include "OBJ_Loader.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <filesystem>
|
||||
|
||||
#define OBJL_VEC2_TO_EIGEN_VECTOR(objl_v) \
|
||||
Eigen::Vector2d { objl_v.X, objl_v.Y }
|
||||
|
@ -12,8 +12,9 @@
|
|||
Eigen::Vector3d { objl_v.X, objl_v.Y, objl_v.Z }
|
||||
|
||||
Mesh::Mesh(const std::vector<std::shared_ptr<Vertex>> &vertices,
|
||||
const std::vector<Triangle> &primitives)
|
||||
: vertices_(vertices), primitives_(primitives) {}
|
||||
const std::vector<Triangle> &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 {
|
||||
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) {
|
||||
const auto &obj_path = std::filesystem::path(file_path);
|
||||
const auto &material_directory = obj_path.parent_path();
|
||||
|
||||
objl::Loader loader{};
|
||||
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());
|
||||
|
||||
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>(
|
||||
OBJL_VEC3_TO_EIGEN_VECTOR(mesh.Vertices[i].Position),
|
||||
OBJL_VEC3_TO_EIGEN_VECTOR(mesh.Vertices[i].Normal),
|
||||
OBJL_VEC2_TO_EIGEN_VECTOR(mesh.Vertices[i].TextureCoordinate)));
|
||||
}
|
||||
|
||||
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],
|
||||
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;
|
||||
}
|
||||
|
|
15
src/mesh.h
15
src/mesh.h
|
@ -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)
|
||||
|
||||
#pragma once
|
||||
|
@ -7,21 +7,32 @@
|
|||
#include <memory>
|
||||
|
||||
#include "common.h"
|
||||
#include "phone_material.h"
|
||||
#include "triangle.h"
|
||||
|
||||
class Mesh {
|
||||
public:
|
||||
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);
|
||||
|
||||
public:
|
||||
Point2d get_texture_coordinate(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::shared_ptr<PhoneMaterial> &get_material() { return material_; }
|
||||
const std::shared_ptr<PhoneMaterial> &get_material() const {
|
||||
return material_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Vertex>> vertices_;
|
||||
std::vector<Triangle> primitives_;
|
||||
|
||||
std::shared_ptr<PhoneMaterial> material_;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include "minus_renderer.h"
|
||||
#include "rasterizer.h"
|
||||
|
@ -62,20 +63,21 @@ TransformMatrix MinusRenderer::view_port_transform(const float width,
|
|||
{0, 0, 0, 1}};
|
||||
}
|
||||
|
||||
Point3d MinusRenderer::calculate_barycentric_coordinate(const Triangle &t,
|
||||
std::tuple<double, double, double>
|
||||
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())) /
|
||||
(-(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};
|
||||
return {alpha, beta, gamma};
|
||||
}
|
||||
|
||||
void MinusRenderer::model_transform(const TransformMatrix &mtx) {
|
||||
|
@ -104,41 +106,56 @@ cv::Mat MinusRenderer::render(const int resolution_width,
|
|||
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();
|
||||
const auto &shading_points = rasterizer.rasterize(meshes);
|
||||
assert(!shading_points.empty());
|
||||
cv::Mat depth_image(shading_points.size(), (shading_points[0]).size(),
|
||||
CV_8UC1);
|
||||
cv::Mat color_image(shading_points.size(), (shading_points[0]).size(),
|
||||
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 &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);
|
||||
const auto &p = shading_points[y][x];
|
||||
if (p.triangle.mesh_index >= 0 && p.triangle.mesh_index < meshes.size()) {
|
||||
const auto &mesh = meshes[p.triangle.mesh_index];
|
||||
const auto &primitives = mesh.get_primitives();
|
||||
if (p.triangle.triangle_index >= 0 &&
|
||||
p.triangle.triangle_index < primitives.size()) {
|
||||
const auto &triangle = primitives[p.triangle.triangle_index];
|
||||
const auto &[alpha, beta, gamma] = calculate_barycentric_coordinate(
|
||||
triangle, Point2d{x + 0.5, y + 0.5});
|
||||
|
||||
const auto &triangle_indices = triangle.get_vertex_index();
|
||||
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) {
|
||||
|
|
|
@ -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)
|
||||
|
||||
#pragma once
|
||||
|
@ -24,8 +24,8 @@ private:
|
|||
static float calculate_width(const float height, const float ratio);
|
||||
static TransformMatrix view_port_transform(const float width,
|
||||
const float height);
|
||||
static Point3d calculate_barycentric_coordinate(const Triangle &t,
|
||||
const Point2d &p);
|
||||
static std::tuple<double, double, double>
|
||||
calculate_barycentric_coordinate(const Triangle &t, const Point2d &p);
|
||||
|
||||
private:
|
||||
TransformMatrix squish_transform();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_;
|
||||
};
|
|
@ -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)
|
||||
|
||||
#include <limits>
|
||||
|
@ -14,10 +14,40 @@ Rasterizer::Rasterizer(const int width, const int height)
|
|||
height, std::vector<RasterizerResult>(width, RasterizerResult{}))) {}
|
||||
|
||||
std::vector<std::vector<RasterizerResult>>
|
||||
Rasterizer::rasterize(const std::vector<Triangle> &primitives) {
|
||||
auto partial_rasterize = [&primitives, this](const int begin, const int end) {
|
||||
for (int idx = begin; idx < end; ++idx) {
|
||||
const auto &t = primitives[idx];
|
||||
Rasterizer::rasterize(const std::vector<Mesh> &meshes) {
|
||||
for (int m_id = 0; m_id < meshes.size(); ++m_id) {
|
||||
const auto &primitives = (meshes[m_id]).get_primitives();
|
||||
|
||||
const int thread_num = 8;
|
||||
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(
|
||||
[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();
|
||||
}
|
||||
}
|
||||
return shading_points_;
|
||||
}
|
||||
|
||||
void Rasterizer::rasterize(const int mesh_idx,
|
||||
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();
|
||||
|
@ -28,39 +58,17 @@ Rasterizer::rasterize(const std::vector<Triangle> &primitives) {
|
|||
|
||||
for (int i = y_min; i < y_max; ++i) {
|
||||
for (int j = x_min; j <= x_max; ++j) {
|
||||
auto &property = (this->shading_points_)[i][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_index = idx;
|
||||
property.triangle.mesh_index = mesh_idx;
|
||||
property.triangle.triangle_index = t_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
std::vector<std::vector<RasterizerResult>> Rasterizer::get_picture() const {
|
||||
return shading_points_;
|
||||
}
|
||||
|
||||
void Rasterizer::reset() {
|
||||
|
|
|
@ -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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mesh.h"
|
||||
#include "triangle.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <vector>
|
||||
|
||||
typedef struct RasterizerResult {
|
||||
double depth{-std::numeric_limits<double>::infinity()};
|
||||
struct {
|
||||
int32_t mesh_index{-1};
|
||||
int64_t triangle_index{-1};
|
||||
} triangle;
|
||||
} RasterizerResult;
|
||||
|
||||
class Rasterizer {
|
||||
|
@ -18,15 +22,18 @@ public:
|
|||
|
||||
public:
|
||||
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();
|
||||
|
||||
private:
|
||||
static std::pair<bool, double> inside(const Point2d &p_screen,
|
||||
const Triangle &t);
|
||||
|
||||
private:
|
||||
void rasterize(const int mesh_idx, const std::vector<Triangle> &primitives,
|
||||
const int begin, const int end);
|
||||
|
||||
private:
|
||||
int width_;
|
||||
int height_;
|
||||
|
|
|
@ -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)
|
||||
|
||||
#include "triangle.h"
|
||||
|
|
|
@ -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)
|
||||
|
||||
#pragma once
|
||||
|
|
|
@ -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])};
|
||||
}
|
|
@ -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);
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@bytedance.com (tianlei.richard)
|
||||
// Copyright 2024 SquareBlock Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
||||
|
||||
#include "common.h"
|
||||
#include <cmath>
|
||||
|
|
Loading…
Reference in New Issue