From c59fe00b845ef25240ea1ee36b224500f6dc6013 Mon Sep 17 00:00:00 2001 From: "tianlei.richard" Date: Fri, 22 Mar 2024 20:12:09 +0800 Subject: [PATCH] support texture mapping. --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 9 +++- src/camera.cc | 2 +- src/camera.h | 2 +- src/common.h | 2 +- src/main.cc | 20 ++++----- src/material.cc | 2 - src/material.h | 4 -- src/mesh.cc | 28 +++++++++---- src/mesh.h | 15 ++++++- src/minus_renderer.cc | 79 +++++++++++++++++++++-------------- src/minus_renderer.h | 6 +-- src/phone_material.cc | 49 ++++++++++++++++++++++ src/phone_material.h | 27 ++++++++++++ src/rasterizer.cc | 88 +++++++++++++++++++++------------------ src/rasterizer.h | 15 +++++-- src/triangle.cc | 2 +- src/triangle.h | 2 +- src/util/interpolation.cc | 10 +++++ src/util/interpolation.h | 23 ++++++++++ src/util/math_util.h | 4 +- 21 files changed, 278 insertions(+), 113 deletions(-) delete mode 100644 src/material.cc delete mode 100644 src/material.h create mode 100644 src/phone_material.cc create mode 100644 src/phone_material.h create mode 100644 src/util/interpolation.cc create mode 100644 src/util/interpolation.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c09b41..0abc511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f89bc3c..db0adfd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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}) diff --git a/src/camera.cc b/src/camera.cc index 201215d..c7ec665 100644 --- a/src/camera.cc +++ b/src/camera.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 "camera.h" diff --git a/src/camera.h b/src/camera.h index 9b37f0c..7677f84 100644 --- a/src/camera.h +++ b/src/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" diff --git a/src/common.h b/src/common.h index 6bc3868..ea36e91 100644 --- a/src/common.h +++ b/src/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 diff --git a/src/main.cc b/src/main.cc index 5bfe33c..3be5589 100644 --- a/src/main.cc +++ b/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 @@ -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(static_cast(texture)), ImVec2(image.cols, image.rows)); diff --git a/src/material.cc b/src/material.cc deleted file mode 100644 index c316a7e..0000000 --- a/src/material.cc +++ /dev/null @@ -1,2 +0,0 @@ -// Copyright 2024 Bytedance Inc. All Rights Reserved. -// Author: tianlei.richard@qq.com (tianlei.richard) diff --git a/src/material.h b/src/material.h deleted file mode 100644 index e2f14fc..0000000 --- a/src/material.h +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2024 Bytedance Inc. All Rights Reserved. -// Author: tianlei.richard@qq.com (tianlei.richard) - -#pragma once \ No newline at end of file diff --git a/src/mesh.cc b/src/mesh.cc index 73fe542..d89d794 100644 --- a/src/mesh.cc +++ b/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 #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> &vertices, - const std::vector &primitives) - : vertices_(vertices), primitives_(primitives) {} + const std::vector &primitives, + const std::shared_ptr &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::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::load_mesh(const std::string &file_path) { spdlog::info("Current mesh has {} vertices.", mesh.Vertices.size()); std::vector> 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( 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 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 texture_path; + if (!mesh.MeshMaterial.map_Kd.empty()) { + texture_path.push_back(material_directory / mesh.MeshMaterial.map_Kd); + } + auto material = + std::shared_ptr(new PhoneMaterial(texture_path)); + + res.push_back(Mesh(vertices, primitives, material)); } return res; } diff --git a/src/mesh.h b/src/mesh.h index e7e4e25..85b9795 100644 --- a/src/mesh.h +++ b/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 #include "common.h" +#include "phone_material.h" #include "triangle.h" class Mesh { public: Mesh(const std::vector> &vertices, - const std::vector &primitives); + const std::vector &primitives, + const std::shared_ptr &phone_material); static std::vector 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 &get_primitives() const { return primitives_; }; std::vector &get_primitives() { return primitives_; }; + std::shared_ptr &get_material() { return material_; } + const std::shared_ptr &get_material() const { + return material_; + } + private: std::vector> vertices_; std::vector primitives_; + + std::shared_ptr material_; }; diff --git a/src/minus_renderer.cc b/src/minus_renderer.cc index cb8edf5..334308c 100644 --- a/src/minus_renderer.cc +++ b/src/minus_renderer.cc @@ -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 #include "spdlog/spdlog.h" +#include #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, - const Point2d &p) { +std::tuple +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 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(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(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); + 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 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) { diff --git a/src/minus_renderer.h b/src/minus_renderer.h index e600a73..a0f92f7 100644 --- a/src/minus_renderer.h +++ b/src/minus_renderer.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 @@ -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 + calculate_barycentric_coordinate(const Triangle &t, const Point2d &p); private: TransformMatrix squish_transform(); diff --git a/src/phone_material.cc b/src/phone_material.cc new file mode 100644 index 0000000..eb8bc65 --- /dev/null +++ b/src/phone_material.cc @@ -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 + +PhoneMaterial::PhoneMaterial( + const std::vector &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(x_f, y_f); + const cv::Vec3b &b = texture.at(x_f, y_c); + const cv::Vec3b &c = texture.at(x_c, y_f); + const cv::Vec3b &d = texture.at(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; +} diff --git a/src/phone_material.h b/src/phone_material.h new file mode 100644 index 0000000..2594de9 --- /dev/null +++ b/src/phone_material.h @@ -0,0 +1,27 @@ +// Copyright 2024 SquareBlock Inc. All Rights Reserved. +// Author: tianlei.richard@qq.com (tianlei.richard) + +#pragma once + +#include +#include +#include + +#include "common.h" + +// Bling-Phone Matrerial +class PhoneMaterial { +public: + using TextureId = uint32_t; + + PhoneMaterial(const std::vector &texture_path); + +public: + cv::Vec3b sample_texture(const TextureId texture_id, + const Point2d &texture_coordinate); + +private: + std::vector textures_; + + uint32_t illumination_intensity_; +}; diff --git a/src/rasterizer.cc b/src/rasterizer.cc index b6dad1e..eef104b 100644 --- a/src/rasterizer.cc +++ b/src/rasterizer.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 @@ -14,53 +14,61 @@ Rasterizer::Rasterizer(const int width, const int height) height, std::vector(width, RasterizerResult{}))) {} std::vector> -Rasterizer::rasterize(const std::vector &primitives) { - auto partial_rasterize = [&primitives, this](const int begin, const int end) { - for (int idx = begin; idx < end; ++idx) { - const auto &t = primitives[idx]; - const auto &triangle_points = t.get_vertex_position(); +Rasterizer::rasterize(const std::vector &meshes) { + for (int m_id = 0; m_id < meshes.size(); ++m_id) { + const auto &primitives = (meshes[m_id]).get_primitives(); - 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 = (this->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; - } - } + const int thread_num = 8; + std::vector 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 &primitives, const int begin, + const int end) { + this->rasterize(m_id, primitives, begin, end); + }, + (meshes[m_id]).get_primitives(), begin, end)); + begin = end; } - }; - - const int thread_num = 6; - std::vector 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; + for (auto &t : rasterize_threads) { + t.join(); } - rasterize_threads.push_back(std::thread(partial_rasterize, begin, end)); - begin = end; - } - for (auto &t : rasterize_threads) { - t.join(); } return shading_points_; } -std::vector> Rasterizer::get_picture() const { - return shading_points_; +void Rasterizer::rasterize(const int mesh_idx, + const std::vector &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() { diff --git a/src/rasterizer.h b/src/rasterizer.h index 1883d20..4a97e25 100644 --- a/src/rasterizer.h +++ b/src/rasterizer.h @@ -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 #include typedef struct RasterizerResult { double depth{-std::numeric_limits::infinity()}; - int64_t triangle_index{-1}; + struct { + int32_t mesh_index{-1}; + int64_t triangle_index{-1}; + } triangle; } RasterizerResult; class Rasterizer { @@ -18,15 +22,18 @@ public: public: std::vector> - rasterize(const std::vector &primitives); + rasterize(const std::vector &meshes); - std::vector> get_picture() const; void reset(); private: static std::pair inside(const Point2d &p_screen, const Triangle &t); +private: + void rasterize(const int mesh_idx, const std::vector &primitives, + const int begin, const int end); + private: int width_; int height_; diff --git a/src/triangle.cc b/src/triangle.cc index 7c43329..d71a6e8 100644 --- a/src/triangle.cc +++ b/src/triangle.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 "triangle.h" diff --git a/src/triangle.h b/src/triangle.h index b9d553a..7c291a6 100644 --- a/src/triangle.h +++ b/src/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 diff --git a/src/util/interpolation.cc b/src/util/interpolation.cc new file mode 100644 index 0000000..45cfdb1 --- /dev/null +++ b/src/util/interpolation.cc @@ -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])}; +} diff --git a/src/util/interpolation.h b/src/util/interpolation.h new file mode 100644 index 0000000..244fa89 --- /dev/null +++ b/src/util/interpolation.h @@ -0,0 +1,23 @@ +// Copyright 2024 SquareBlock Inc. All Rights Reserved. +// Author: tianlei.richard@qq.com (tianlei.richard) + +#pragma once + +#include + +template T lerp(const float t, const T &a, const T &b) { + return static_cast(t * b) + (1 - t) * static_cast(a); +} + +template +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); diff --git a/src/util/math_util.h b/src/util/math_util.h index 06e2756..dbaf968 100644 --- a/src/util/math_util.h +++ b/src/util/math_util.h @@ -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