complete phone shading impl.

This commit is contained in:
tianlei.richard 2024-03-29 18:09:16 +08:00
parent af09ed9311
commit acd472bacf
11 changed files with 137 additions and 131 deletions

View File

@ -11,31 +11,39 @@
#define OBJL_VEC3_TO_EIGEN_VECTOR(objl_v) \ #define OBJL_VEC3_TO_EIGEN_VECTOR(objl_v) \
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<Vertex> &vertices,
const std::vector<Triangle> &primitives, const std::vector<std::array<size_t, 3>> &indices,
const std::shared_ptr<PhoneMaterial> &phone_material) const std::shared_ptr<PhoneMaterial> &phone_material)
: vertices_(vertices), primitives_(primitives), material_(phone_material) {} : vertices_(vertices), indices_(indices), material_(phone_material) {}
std::vector<std::shared_ptr<Vertex>>::size_type Mesh::get_vertex_size() const { std::vector<Vertex> &Mesh::get_vertices() { return vertices_; }
std::vector<Vertex>::size_type Mesh::get_vertex_size() const {
return vertices_.size(); return vertices_.size();
}; };
const decltype(Vertex::texture_coordinate) & const decltype(Vertex::texture_coordinate) &
Mesh::get_texture_coordinate(const unsigned int index) const { Mesh::get_texture_coordinate(const unsigned int index) const {
return (vertices_[index])->texture_coordinate; return (vertices_[index]).texture_coordinate;
} }
Point3d Mesh::get_normal_vector(const unsigned int index) const { Point3d Mesh::get_normal_vector(const unsigned int index) const {
return (vertices_[index])->normal; return (vertices_[index]).normal;
} }
const std::vector<Triangle> &Mesh::get_primitives() const { std::vector<Triangle> Mesh::get_primitives() const {
return primitives_; std::vector<Triangle> primitives;
}; for (const auto &idx : indices_) {
primitives.push_back(Triangle(vertices_, idx[0], idx[1], idx[2]));
}
return primitives;
}
std::vector<Triangle> &Mesh::get_primitives() { return primitives_; }; Triangle Mesh::get_primitive(const size_t index) const {
assert(index >= 0 && index < indices_.size());
std::shared_ptr<PhoneMaterial> &Mesh::get_material() { return material_; } return Triangle(vertices_, indices_[index][0], indices_[index][1],
indices_[index][2]);
}
const std::shared_ptr<PhoneMaterial> &Mesh::get_material() const { const std::shared_ptr<PhoneMaterial> &Mesh::get_material() const {
return material_; return material_;
@ -54,19 +62,19 @@ std::vector<Mesh> Mesh::load_mesh(
for (const auto &mesh : loader.LoadedMeshes) { for (const auto &mesh : loader.LoadedMeshes) {
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<Vertex> vertices;
for (decltype(mesh.Vertices)::size_type i = 0; i < mesh.Vertices.size(); for (decltype(mesh.Vertices)::size_type i = 0; i < mesh.Vertices.size();
i++) { i++) {
vertices.push_back(std::make_shared<Vertex>( vertices.push_back(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<std::array<size_t, 3>> indices;
for (decltype(mesh.Indices)::size_type i = 0; i < mesh.Indices.size(); for (decltype(mesh.Indices)::size_type i = 0; i < mesh.Indices.size();
i += 3) { i += 3) {
primitives.push_back(Triangle(vertices, mesh.Indices[i], indices.push_back(
mesh.Indices[i + 1], mesh.Indices[i + 2])); {mesh.Indices[i], mesh.Indices[i + 1], mesh.Indices[i + 2]});
} }
std::unordered_map<Texture::TextureType, std::shared_ptr<Texture>> textures; std::unordered_map<Texture::TextureType, std::shared_ptr<Texture>> textures;
@ -82,7 +90,7 @@ std::vector<Mesh> Mesh::load_mesh(
auto material = std::make_shared<PhoneMaterial>( auto material = std::make_shared<PhoneMaterial>(
textures, std::make_shared<Lamp>(Point3d{}, 16.)); textures, std::make_shared<Lamp>(Point3d{}, 16.));
res.push_back(Mesh(vertices, primitives, material)); res.push_back(Mesh(vertices, indices, material));
} }
return res; return res;
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <array>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
@ -12,8 +13,8 @@
class Mesh { class Mesh {
public: public:
Mesh(const std::vector<std::shared_ptr<Vertex>> &vertices, Mesh(const std::vector<Vertex> &vertices,
const std::vector<Triangle> &primitives, const std::vector<std::array<size_t, 3>> &indices,
const std::shared_ptr<PhoneMaterial> &phone_material); const std::shared_ptr<PhoneMaterial> &phone_material);
static std::vector<Mesh> load_mesh( static std::vector<Mesh> load_mesh(
@ -21,22 +22,23 @@ public:
const std::unordered_map<Texture::TextureType, std::string> textures); const std::unordered_map<Texture::TextureType, std::string> textures);
public: public:
std::vector<std::shared_ptr<Vertex>>::size_type get_vertex_size() const; std::vector<Vertex> &get_vertices();
std::vector<Vertex>::size_type get_vertex_size() const;
const decltype(Vertex::texture_coordinate) & const decltype(Vertex::texture_coordinate) &
get_texture_coordinate(const unsigned int index) const; 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; std::vector<Triangle> get_primitives() const;
std::vector<Triangle> &get_primitives(); Triangle get_primitive(const size_t index) const;
std::shared_ptr<PhoneMaterial> &get_material();
const std::shared_ptr<PhoneMaterial> &get_material() const; const std::shared_ptr<PhoneMaterial> &get_material() const;
private: private:
std::vector<std::shared_ptr<Vertex>> vertices_; std::vector<Vertex> vertices_;
std::vector<Triangle> primitives_; std::vector<std::array<size_t, 3>> indices_;
std::shared_ptr<PhoneMaterial> material_; std::shared_ptr<PhoneMaterial> material_;
}; };

View File

@ -19,8 +19,6 @@ MinusRenderer::MinusRenderer(float near, float far, float fov,
void MinusRenderer::set_meshes(const std::vector<Mesh> &meshes) { void MinusRenderer::set_meshes(const std::vector<Mesh> &meshes) {
meshes_ = meshes; meshes_ = meshes;
spdlog::info("Mesh size: {}, the primitives size of the first mesh: {}",
meshes_.size(), meshes_.front().get_primitives().size());
} }
float MinusRenderer::calculate_height(const float fov, const float near) { float MinusRenderer::calculate_height(const float fov, const float near) {
@ -94,35 +92,38 @@ MinusRenderer::construct_transform(const int resolution_width,
std::tuple<double, double, double> std::tuple<double, double, double>
MinusRenderer::calculate_barycentric_coordinate(const Triangle &t, MinusRenderer::calculate_barycentric_coordinate(const Triangle &t,
const Point2d &p) { const Point3d &p) {
const auto &points = t.get_vertex_position(); const auto &points = t.get_vertex_position();
const auto &A = (points[0]).head(2); const auto &pa = points[0];
const auto &B = (points[1]).head(2); const auto &pb = points[1];
const auto &C = (points[2]).head(2); const auto &pc = points[2];
double alpha = const auto &triangle_normal = t.normal_vector();
(-(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())); const double squared_area = triangle_normal.norm() * triangle_normal.norm();
double beta = const double alpha =
(-(p.x() - C.x()) * (A.y() - C.y()) + (p.y() - C.y()) * (A.x() - C.x())) / (triangle_normal.dot((pc - pb).cross(p - pb))) / squared_area;
(-(B.x() - C.x()) * (A.y() - C.y()) + (B.y() - C.y()) * (A.x() - C.x())); const double beta =
double gamma = 1. - alpha - beta; (triangle_normal.dot((pa - pc).cross(p - pc))) / squared_area;
const double gamma =
(triangle_normal.dot((pb - pa).cross(p - pa))) / squared_area;
return {alpha, beta, gamma}; return {alpha, beta, gamma};
} }
void MinusRenderer::model_transform(const TransformMatrix &mtx) { void MinusRenderer::model_transform(const TransformMatrix &mtx) {
for (auto &m : meshes_) { for (auto &m : meshes_) {
for (auto &t : m.get_primitives()) { for (auto &v : m.get_vertices()) {
const auto &[res, _] = apply_transform(mtx, t.get_vertex_position()); v.position = (mtx * v.position.homogeneous()).hnormalized();
t.set_points(res); v.normal = (mtx * v.normal.homogeneous()).hnormalized();
} }
} }
} }
void MinusRenderer::view_transform(const TransformMatrix &mtx) { void MinusRenderer::view_transform(const TransformMatrix &mtx) {
for (auto &m : meshes_) { for (auto &m : meshes_) {
for (auto &t : m.get_primitives()) { for (auto &v : m.get_vertices()) {
const auto &[res, _] = apply_transform(mtx, t.get_vertex_position()); v.position = (mtx * v.position.homogeneous()).hnormalized();
t.set_points(res); v.normal = (mtx * v.normal.homogeneous()).hnormalized();
} }
} }
} }
@ -133,22 +134,16 @@ cv::Mat MinusRenderer::render(const int resolution_width,
const auto [ss_transform, inv_ss_transform] = const auto [ss_transform, inv_ss_transform] =
construct_transform(resolution_width, resolution_height); construct_transform(resolution_width, resolution_height);
// 主要为了把顶点坐标拷贝一份,否则 camera space 的坐标被变换到 screen space,
// 下次渲染时拿到的就不是 camera space 的坐标
std::vector<Mesh> meshes = meshes_;
Rasterizer rasterizer{resolution_width, resolution_height}; Rasterizer rasterizer{resolution_width, resolution_height};
for (int mesh_index = 0; mesh_index < meshes.size(); ++mesh_index) { for (int mesh_index = 0; mesh_index < meshes_.size(); ++mesh_index) {
auto &mesh = meshes[mesh_index]; auto primitives = (meshes_[mesh_index]).get_primitives();
auto &primitives = mesh.get_primitives(); for (auto &t : primitives) {
for (int i = 0; i < primitives.size(); ++i) { t.set_points(apply_transform(ss_transform, t.get_vertex_position()));
auto &t = primitives[i];
const auto &triangle_vertices = t.get_vertex_position();
const auto &[res, _] =
apply_transform(ss_transform, t.get_vertex_position());
t.set_points(res);
} }
rasterizer.rasterize(mesh_index, primitives);
} }
const auto &shading_points = rasterizer.rasterize(meshes);
const auto &shading_points = rasterizer.get_shading_points();
assert(!shading_points.empty()); assert(!shading_points.empty());
cv::Mat color_image(shading_points.size(), (shading_points[0]).size(), cv::Mat color_image(shading_points.size(), (shading_points[0]).size(),
CV_8UC3); CV_8UC3);
@ -162,23 +157,16 @@ cv::Mat MinusRenderer::render(const int resolution_width,
if (fragment.triangle.mesh_index >= 0 && if (fragment.triangle.mesh_index >= 0 &&
fragment.triangle.mesh_index < meshes_.size()) { fragment.triangle.mesh_index < meshes_.size()) {
const auto &mesh = meshes_[fragment.triangle.mesh_index]; const auto &mesh = meshes_[fragment.triangle.mesh_index];
const auto &primitives = mesh.get_primitives(); if (fragment.depth > -std::numeric_limits<double>::infinity()) {
if (fragment.triangle.triangle_index >= 0 &&
fragment.triangle.triangle_index < primitives.size()) {
const Point3d &position = const Point3d &position =
(inv_ss_transform * (inv_ss_transform *
(Point3d{x + 0.5, y + 0.5, fragment.depth}.homogeneous())) (Point3d{x + 0.5, y + 0.5, fragment.depth}.homogeneous()))
.hnormalized(); .hnormalized();
spdlog::trace("Screen space potions: ({}, {}, {}), camera space "
"position: ({}, {}, {})",
x + 0.5, y + 0.5, fragment.depth, position.x(),
position.y(), position.z());
const auto &triangle = primitives[fragment.triangle.triangle_index]; const auto &triangle =
mesh.get_primitive(fragment.triangle.triangle_index);
const auto &[alpha, beta, gamma] = const auto &[alpha, beta, gamma] =
calculate_barycentric_coordinate(triangle, position.head(2)); calculate_barycentric_coordinate(triangle, position);
spdlog::trace("barycentric coordinate: ({}, {}, {})", alpha, beta,
gamma);
std::vector<Point2d> triangle_uv; std::vector<Point2d> triangle_uv;
std::vector<Point3d> triangle_normal; std::vector<Point3d> triangle_normal;
@ -191,9 +179,7 @@ cv::Mat MinusRenderer::render(const int resolution_width,
gamma * triangle_uv[2].x(), gamma * triangle_uv[2].x(),
alpha * triangle_uv[0].y() + beta * triangle_uv[1].y() + alpha * triangle_uv[0].y() + beta * triangle_uv[1].y() +
gamma * triangle_uv[2].y()}; gamma * triangle_uv[2].y()};
spdlog::trace("UV: ({}, {}, {})", uv.x(), uv.y()); const auto &normal = -1. * Point3d(alpha * triangle_normal[0].x() +
const auto &normal = Point3d{alpha * triangle_normal[0].x() +
beta * triangle_normal[1].x() + beta * triangle_normal[1].x() +
gamma * triangle_normal[2].x(), gamma * triangle_normal[2].x(),
alpha * triangle_normal[0].y() + alpha * triangle_normal[0].y() +
@ -201,12 +187,10 @@ cv::Mat MinusRenderer::render(const int resolution_width,
gamma * triangle_normal[2].y(), gamma * triangle_normal[2].y(),
alpha * triangle_normal[0].z() + alpha * triangle_normal[0].z() +
beta * triangle_normal[1].z() + beta * triangle_normal[1].z() +
gamma * triangle_normal[2].z()} gamma * triangle_normal[2].z())
.normalized(); .normalized();
spdlog::trace("Normal: ({}, {}, {})", normal.x(), normal.y(),
normal.z());
auto &material = mesh.get_material(); const auto &material = mesh.get_material();
pixel_color = pixel_color =
material->shade(Vertex{position, normal, uv}, Point3d{}); material->shade(Vertex{position, normal, uv}, Point3d{});
} }

View File

@ -24,7 +24,7 @@ private:
static float calculate_height(const float fov, const float near); static float calculate_height(const float fov, const float near);
static float calculate_width(const float height, const float ratio); static float calculate_width(const float height, const float ratio);
static std::tuple<double, double, double> static std::tuple<double, double, double>
calculate_barycentric_coordinate(const Triangle &t, const Point2d &p); calculate_barycentric_coordinate(const Triangle &t, const Point3d &p);
private: private:
std::pair<TransformMatrix, TransformMatrix> std::pair<TransformMatrix, TransformMatrix>

View File

@ -10,19 +10,19 @@ PhoneMaterial::PhoneMaterial(
const std::unordered_map<Texture::TextureType, std::shared_ptr<Texture>> const std::unordered_map<Texture::TextureType, std::shared_ptr<Texture>>
&textures, &textures,
const std::shared_ptr<Lamp> &lamp) const std::shared_ptr<Lamp> &lamp)
: point_lamp_(lamp), textures_(textures), Ka(cv::Vec3b{32, 32, 32}), : point_lamp_(lamp), textures_(textures), Ka(cv::Vec3b{24, 24, 24}),
Ks(cv::Vec3b(64, 64, 64)), Ks(cv::Vec3b(48, 48, 48)),
specular_attenuation_factor_(defaultAttenuationFactor) { specular_attenuation_factor_(defaultAttenuationFactor) {
spdlog::info("Specular attenuation factor: {}", specular_attenuation_factor_); spdlog::info("Specular attenuation factor: {}", specular_attenuation_factor_);
} }
cv::Vec3b PhoneMaterial::shade(const Vertex &shading_point, cv::Vec3b PhoneMaterial::shade(const Vertex &shading_point,
const Point3d &view_point) { const Point3d &view_point) const {
cv::Vec3b shading_res{0, 0, 0}; cv::Vec3b shading_res{0, 0, 0};
// Diffuse // Diffuse
assert(textures_.find(Texture::DiffuseMap) != textures_.end()); assert(textures_.find(Texture::DiffuseMap) != textures_.end());
const auto &diffuse_map = textures_[Texture::DiffuseMap]; const auto &diffuse_map = textures_.at(Texture::DiffuseMap);
const auto &Kd = diffuse_map->sample(shading_point.texture_coordinate); const auto &Kd = diffuse_map->sample(shading_point.texture_coordinate);
const auto &point2light_vector = const auto &point2light_vector =

View File

@ -17,10 +17,10 @@ public:
std::shared_ptr<Texture>> &textures, std::shared_ptr<Texture>> &textures,
const std::shared_ptr<Lamp> &lamp); const std::shared_ptr<Lamp> &lamp);
cv::Vec3b shade(const Vertex &shading_point, const Point3d &view_point); cv::Vec3b shade(const Vertex &shading_point, const Point3d &view_point) const;
private: private:
static constexpr int defaultAttenuationFactor = 16; static constexpr int defaultAttenuationFactor = 12;
private: private:
std::shared_ptr<Lamp> point_lamp_; std::shared_ptr<Lamp> point_lamp_;

View File

@ -13,11 +13,8 @@ Rasterizer::Rasterizer(const int width, const int height)
shading_points_(std::vector<std::vector<RasterizerResult>>( shading_points_(std::vector<std::vector<RasterizerResult>>(
height, std::vector<RasterizerResult>(width, RasterizerResult{}))) {} height, std::vector<RasterizerResult>(width, RasterizerResult{}))) {}
std::vector<std::vector<RasterizerResult>> void Rasterizer::rasterize(const int mesh_idx,
Rasterizer::rasterize(const std::vector<Mesh> &meshes) { const std::vector<Triangle> &primitives) {
for (int m_id = 0; m_id < meshes.size(); ++m_id) {
const auto &primitives = (meshes[m_id]).get_primitives();
const int thread_num = 8; const int thread_num = 8;
std::vector<std::thread> rasterize_threads; std::vector<std::thread> rasterize_threads;
for (int begin = 0, offset = primitives.size() / thread_num, for (int begin = 0, offset = primitives.size() / thread_num,
@ -29,18 +26,16 @@ Rasterizer::rasterize(const std::vector<Mesh> &meshes) {
remainer -= 1; remainer -= 1;
} }
rasterize_threads.push_back(std::thread( rasterize_threads.push_back(std::thread(
[this, m_id](const std::vector<Triangle> &primitives, const int begin, [this, mesh_idx](const std::vector<Triangle> &primitives,
const int end) { const int begin, const int end) {
this->rasterize(m_id, primitives, begin, end); this->rasterize(mesh_idx, primitives, begin, end);
}, },
(meshes[m_id]).get_primitives(), begin, end)); primitives, begin, end));
begin = end; begin = end;
} }
for (auto &t : rasterize_threads) { for (auto &t : rasterize_threads) {
t.join(); t.join();
} }
}
return shading_points_;
} }
void Rasterizer::rasterize(const int mesh_idx, void Rasterizer::rasterize(const int mesh_idx,
@ -71,6 +66,11 @@ void Rasterizer::rasterize(const int mesh_idx,
} }
} }
const std::vector<std::vector<RasterizerResult>> &
Rasterizer::get_shading_points() const {
return shading_points_;
}
void Rasterizer::reset() { void Rasterizer::reset() {
shading_points_ = std::vector<std::vector<RasterizerResult>>( shading_points_ = std::vector<std::vector<RasterizerResult>>(
height_, std::vector<RasterizerResult>(width_, RasterizerResult{})); height_, std::vector<RasterizerResult>(width_, RasterizerResult{}));
@ -80,7 +80,7 @@ std::pair<bool, double> Rasterizer::inside(const Point2d &p_screen,
const Triangle &t) { const Triangle &t) {
const auto points = t.get_vertex_position(); const auto points = t.get_vertex_position();
const auto plane_normal = t.normal_vector(); const auto plane_normal = t.unit_normal_vector();
const auto plane_point = points[0]; const auto plane_point = points[0];
const auto z_screen = const auto z_screen =
plane_point.z() - (plane_normal.x() * (p_screen.x() - plane_point.x()) + plane_point.z() - (plane_normal.x() * (p_screen.x() - plane_point.x()) +

View File

@ -21,9 +21,9 @@ public:
Rasterizer(const int width, const int height); Rasterizer(const int width, const int height);
public: public:
std::vector<std::vector<RasterizerResult>> void rasterize(const int mesh_idx, const std::vector<Triangle> &primitives);
rasterize(const std::vector<Mesh> &meshes);
const std::vector<std::vector<RasterizerResult>> &get_shading_points() const;
void reset(); void reset();
private: private:

View File

@ -9,11 +9,11 @@ Triangle::Triangle(const Point3d &a, unsigned int idx_a, const Point3d &b,
unsigned int idx_b, const Point3d &c, unsigned int idx_c) unsigned int idx_b, const Point3d &c, unsigned int idx_c)
: indices_({idx_a, idx_b, idx_c}), vertices_({a, b, c}) {} : indices_({idx_a, idx_b, idx_c}), vertices_({a, b, c}) {}
Triangle::Triangle(const std::vector<std::shared_ptr<Vertex>> &vertices, Triangle::Triangle(const std::vector<Vertex> &vertices, unsigned int idx_a,
unsigned int idx_a, unsigned int idx_b, unsigned int idx_c) unsigned int idx_b, unsigned int idx_c)
: indices_({idx_a, idx_b, idx_c}), : indices_({idx_a, idx_b, idx_c}),
vertices_({(vertices[idx_a])->position, (vertices[idx_b])->position, vertices_({(vertices[idx_a]).position, (vertices[idx_b]).position,
(vertices[idx_c])->position}) {} (vertices[idx_c]).position}) {}
std::vector<unsigned int> Triangle::get_vertex_index() const { std::vector<unsigned int> Triangle::get_vertex_index() const {
return {indices_[0], indices_[1], indices_[2]}; return {indices_[0], indices_[1], indices_[2]};
@ -45,8 +45,12 @@ BBox Triangle::axis_align_bbox() const {
return BBox{x_min, y_min, (x_max - x_min + 1), (y_max - y_min + 1)}; return BBox{x_min, y_min, (x_max - x_min + 1), (y_max - y_min + 1)};
} }
Vector3d Triangle::unit_normal_vector() const {
return normal_vector().normalized();
}
Vector3d Triangle::normal_vector() const { Vector3d Triangle::normal_vector() const {
const auto v1 = vertices_[1] - vertices_[0]; const auto v1 = vertices_[1] - vertices_[0];
const auto v2 = vertices_[2] - vertices_[1]; const auto v2 = vertices_[2] - vertices_[1];
return v1.cross(v2).normalized(); return v1.cross(v2);
} }

View File

@ -11,8 +11,8 @@ class Triangle {
public: public:
Triangle(const Point3d &a, unsigned int idx_a, const Point3d &b, Triangle(const Point3d &a, unsigned int idx_a, const Point3d &b,
unsigned int idx_b, const Point3d &c, unsigned int idx_c); unsigned int idx_b, const Point3d &c, unsigned int idx_c);
Triangle(const std::vector<std::shared_ptr<Vertex>> &vertices, Triangle(const std::vector<Vertex> &vertices, unsigned int idx_a,
unsigned int idx_a, unsigned int idx_b, unsigned int idx_c); unsigned int idx_b, unsigned int idx_c);
public: public:
std::vector<unsigned int> get_vertex_index() const; std::vector<unsigned int> get_vertex_index() const;
@ -22,6 +22,7 @@ public:
public: public:
BBox axis_align_bbox() const; BBox axis_align_bbox() const;
Vector3d normal_vector() const; Vector3d normal_vector() const;
Vector3d unit_normal_vector() const;
private: private:
std::array<unsigned int, 3> indices_; std::array<unsigned int, 3> indices_;

View File

@ -11,14 +11,21 @@ bool fequal(const FloatType a, const FloatType b) {
} }
template <int d> template <int d>
std::pair<std::vector<Eigen::Vector<double, d>>, std::vector<double>> std::vector<Eigen::Vector<double, d>>
apply_transform(const TransformMatrix &mtx, apply_transform(const TransformMatrix &mtx,
const std::vector<Eigen::Vector<double, d>> &points) { const std::vector<Eigen::Vector<double, d>> &points) {
std::pair<std::vector<Eigen::Vector<double, d>>, std::vector<double>> res{}; std::vector<Eigen::Vector<double, d>> res{};
for (const auto &p : points) { for (const auto &p : points) {
const auto &transform_res = mtx * p.homogeneous(); const auto &transform_res = mtx * p.homogeneous();
res.first.push_back(transform_res.hnormalized()); res.push_back(transform_res.hnormalized());
res.second.push_back(transform_res.w());
} }
return res; return res;
} }
template <int d>
void apply_transform_in_place(const TransformMatrix &mtx,
std::vector<Eigen::Vector<double, d>> &points) {
for (auto &p : points) {
p = mtx * p.homogeneous().hnormalized();
}
}