From af09ed9311ab761e47cb2ba0b3e07929e7417321 Mon Sep 17 00:00:00 2001 From: "tianlei.richard" Date: Thu, 28 Mar 2024 21:55:30 +0800 Subject: [PATCH] debug phone shading, there are still some problems, may normal related. --- src/mesh.cc | 2 +- src/minus_renderer.cc | 165 ++++++++++++++++++++++++------------------ src/minus_renderer.h | 9 +-- src/phone_material.cc | 2 +- 4 files changed, 100 insertions(+), 78 deletions(-) diff --git a/src/mesh.cc b/src/mesh.cc index 183ef9e..23663b9 100644 --- a/src/mesh.cc +++ b/src/mesh.cc @@ -80,7 +80,7 @@ std::vector Mesh::load_mesh( mesh.MeshMaterial.map_Kd)}); } auto material = std::make_shared( - textures, std::make_shared(Point3d{}, 192.)); + textures, std::make_shared(Point3d{}, 16.)); res.push_back(Mesh(vertices, primitives, material)); } diff --git a/src/minus_renderer.cc b/src/minus_renderer.cc index b888a1a..00c172a 100644 --- a/src/minus_renderer.cc +++ b/src/minus_renderer.cc @@ -4,6 +4,7 @@ #include #include "spdlog/spdlog.h" +#include #include #include "minus_renderer.h" @@ -11,8 +12,7 @@ MinusRenderer::MinusRenderer(float near, float far, float fov, float aspect_ratio) - : near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio), - projection_matrix_(orthographic_transform() * squish_transform()) { + : near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio) { spdlog::info("near: {}, far: {}, fov: {}, aspect ratio: {}", near_, far_, fov_, aspect_ratio_); } @@ -31,15 +31,22 @@ float MinusRenderer::calculate_width(const float height, const float ratio) { return height * ratio; } -TransformMatrix MinusRenderer::squish_transform() { - // Frustum to Cuboid - return TransformMatrix{{near_, 0, 0, 0}, - {0, near_, 0, 0}, - {0, 0, near_ + far_, -near_ * far_}, - {0, 0, 1, 0}}; -} +std::pair +MinusRenderer::construct_transform(const int resolution_width, + const int resolution_height) const { + // Squish Transform + const auto &squish_transform = + TransformMatrix{{near_, 0, 0, 0}, + {0, near_, 0, 0}, + {0, 0, near_ + far_, -near_ * far_}, + {0, 0, 1, 0}}; + const auto &inv_squish_transform = + TransformMatrix{{1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 0, near_}, + {0, 0, -1. / far_, (near_ + far_) / far_}}; -TransformMatrix MinusRenderer::orthographic_transform() { + // Orthographic transform const float height = calculate_height(fov_, near_); const float width = calculate_width(height, aspect_ratio_); const float right = width * 0.5; @@ -47,26 +54,42 @@ TransformMatrix MinusRenderer::orthographic_transform() { const float top = height * 0.5; const float bottom = -top; - TransformMatrix m{{1, 0, 0, -0.5 * (right - left)}, - {0, 1, 0, -0.5 * (top - bottom)}, - {0, 0, 1, -0.5 * (far_ - near_)}, - {0, 0, 0, 1}}; - - m = TransformMatrix{{2 / (right - left), 0, 0, 0}, + const auto &ortho_transform = + TransformMatrix{{2 / (right - left), 0, 0, 0}, {0, 2 / (top - bottom), 0, 0}, {0, 0, 2 / std::fabs(far_ - near_), 0}, {0, 0, 0, 1}} * - m; + TransformMatrix{{1, 0, 0, -0.5 * (right - left)}, + {0, 1, 0, -0.5 * (top - bottom)}, + {0, 0, 1, -0.5 * (far_ - near_)}, + {0, 0, 0, 1}}; + const auto &inv_ortho_transform = TransformMatrix{ + {(right - left) / 2., 0, 0, 0.5 * (right - left)}, + {0, (top - bottom) / 2., 0, 0.5 * (top - bottom)}, + {0, 0, std::fabs(far_ - near_) / 2., 0.5 * (far_ - near_)}, + {0, 0, 0, 1}}; - return m; -} + // View port transform + const auto &view_port_transform = + TransformMatrix{{resolution_width / 2., 0, 0, resolution_width * 0.5}, + {0, resolution_height / 2., 0, resolution_height * 0.5}, + {0, 0, 1, 0}, + {0, 0, 0, 1}}; + const auto &inv_view_port_transform = + TransformMatrix{{2. / resolution_width, 0, 0, 0}, + {0, 2. / resolution_height, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1}} * + TransformMatrix{{1, 0, 0, -resolution_width * 0.5}, + {0, 1, 0, -resolution_height * 0.5}, + {0, 0, 1, 0}, + {0, 0, 0, 1}}; -TransformMatrix MinusRenderer::view_port_transform(const float width, - const float height) { - return TransformMatrix{{width * 0.5, 0, 0, width * 0.5}, - {0, height * 0.5, 0, height * 0.5}, - {0, 0, 1, 0}, - {0, 0, 0, 1}}; + const auto &ss_transform = + view_port_transform * ortho_transform * squish_transform; + const auto &inv_ss_transform = + inv_squish_transform * inv_ortho_transform * inv_view_port_transform; + return {ss_transform, inv_ss_transform}; } std::tuple @@ -106,26 +129,22 @@ void MinusRenderer::view_transform(const TransformMatrix &mtx) { cv::Mat MinusRenderer::render(const int resolution_width, const int resolution_height) { + // 构造 camera space -> screen space 的变换矩阵 + const auto [ss_transform, inv_ss_transform] = + construct_transform(resolution_width, resolution_height); + + // 主要为了把顶点坐标拷贝一份,否则 camera space 的坐标被变换到 screen space, + // 下次渲染时拿到的就不是 camera space 的坐标 std::vector meshes = meshes_; - std::vector> perspective_coeff(meshes.size()); Rasterizer rasterizer{resolution_width, resolution_height}; for (int mesh_index = 0; mesh_index < meshes.size(); ++mesh_index) { auto &mesh = meshes[mesh_index]; auto &primitives = mesh.get_primitives(); - perspective_coeff[mesh_index] = - std::vector(mesh.get_vertex_size(), 1.); for (int i = 0; i < primitives.size(); ++i) { auto &t = primitives[i]; const auto &triangle_vertices = t.get_vertex_position(); - const auto &[projective_res, w] = - apply_transform(projection_matrix_, triangle_vertices); - const auto &indices = t.get_vertex_index(); - for (int j = 0; j < indices.size(); ++j) { - perspective_coeff[mesh_index][indices[j]] = w[j]; - } - const auto &[res, _] = apply_transform( - view_port_transform(resolution_width, resolution_height), - projective_res); + const auto &[res, _] = + apply_transform(ss_transform, t.get_vertex_position()); t.set_points(res); } } @@ -139,51 +158,57 @@ cv::Mat MinusRenderer::render(const int resolution_width, color_image.at(shading_points.size() - y - 1, x); pixel_color = cv::Vec3b(0, 0, 0); - 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 &fragment = shading_points[y][x]; + if (fragment.triangle.mesh_index >= 0 && + fragment.triangle.mesh_index < meshes_.size()) { + const auto &mesh = meshes_[fragment.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}); + if (fragment.triangle.triangle_index >= 0 && + fragment.triangle.triangle_index < primitives.size()) { + const Point3d &position = + (inv_ss_transform * + (Point3d{x + 0.5, y + 0.5, fragment.depth}.homogeneous())) + .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 &[alpha, beta, gamma] = + calculate_barycentric_coordinate(triangle, position.head(2)); + spdlog::trace("barycentric coordinate: ({}, {}, {})", alpha, beta, + gamma); std::vector triangle_uv; std::vector triangle_normal; - std::vector w_coeff; for (const auto vertex_index : triangle.get_vertex_index()) { triangle_uv.push_back(mesh.get_texture_coordinate(vertex_index)); triangle_normal.push_back(mesh.get_normal_vector(vertex_index)); - w_coeff.push_back( - perspective_coeff[p.triangle.mesh_index][vertex_index]); } - // TODO(tianlei): 推导一下为什么需要除以下面这个 - // 在 screen space 对 1/w 的插值就相当于在 world space 对 w 的插值 - auto w_reciprocal = alpha * (1. / w_coeff[0]) + - beta * (1. / w_coeff[1]) + - gamma * (1. / w_coeff[2]); - Point2d uv{(alpha * (triangle_uv[0].x() / w_coeff[0]) + - beta * (triangle_uv[1].x() / w_coeff[1]) + - gamma * (triangle_uv[2].x() / w_coeff[2])) / - w_reciprocal, - (alpha * (triangle_uv[0].y() / w_coeff[0]) + - beta * (triangle_uv[1].y() / w_coeff[1]) + - gamma * (triangle_uv[2].y() / w_coeff[2])) / - w_reciprocal}; + Point2d uv{alpha * triangle_uv[0].x() + beta * triangle_uv[1].x() + + gamma * triangle_uv[2].x(), + alpha * triangle_uv[0].y() + beta * triangle_uv[1].y() + + gamma * triangle_uv[2].y()}; + spdlog::trace("UV: ({}, {}, {})", uv.x(), uv.y()); - Point3d normal{ - alpha * triangle_normal[0].x() + beta * triangle_normal[1].x() + - gamma * triangle_normal[2].x(), - alpha * triangle_normal[0].y() + beta * triangle_normal[1].y() + - gamma * triangle_normal[2].y(), - alpha * triangle_normal[0].z() + beta * triangle_normal[1].z() + - gamma * triangle_normal[2].z()}; + const auto &normal = Point3d{alpha * triangle_normal[0].x() + + beta * triangle_normal[1].x() + + gamma * triangle_normal[2].x(), + alpha * triangle_normal[0].y() + + beta * triangle_normal[1].y() + + gamma * triangle_normal[2].y(), + alpha * triangle_normal[0].z() + + beta * triangle_normal[1].z() + + gamma * triangle_normal[2].z()} + .normalized(); + spdlog::trace("Normal: ({}, {}, {})", normal.x(), normal.y(), + normal.z()); auto &material = mesh.get_material(); - pixel_color = material->shade( - Vertex{Point3d{x, y, p.depth}, normal, uv}, Point3d{}); + pixel_color = + material->shade(Vertex{position, normal, uv}, Point3d{}); } } } diff --git a/src/minus_renderer.h b/src/minus_renderer.h index f39628c..95554b3 100644 --- a/src/minus_renderer.h +++ b/src/minus_renderer.h @@ -23,14 +23,13 @@ public: private: static float calculate_height(const float fov, const float near); static float calculate_width(const float height, const float ratio); - static TransformMatrix view_port_transform(const float width, - const float height); static std::tuple calculate_barycentric_coordinate(const Triangle &t, const Point2d &p); private: - TransformMatrix squish_transform(); - TransformMatrix orthographic_transform(); + std::pair + construct_transform(const int resolution_width, + const int resolution_height) const; private: float near_; @@ -38,7 +37,5 @@ private: float fov_; // In radian float aspect_ratio_; - TransformMatrix projection_matrix_; - std::vector meshes_; }; diff --git a/src/phone_material.cc b/src/phone_material.cc index 80b1d1c..b40624d 100644 --- a/src/phone_material.cc +++ b/src/phone_material.cc @@ -10,7 +10,7 @@ PhoneMaterial::PhoneMaterial( const std::unordered_map> &textures, const std::shared_ptr &lamp) - : point_lamp_(lamp), textures_(textures), Ka(cv::Vec3b{16, 16, 16}), + : point_lamp_(lamp), textures_(textures), Ka(cv::Vec3b{32, 32, 32}), Ks(cv::Vec3b(64, 64, 64)), specular_attenuation_factor_(defaultAttenuationFactor) { spdlog::info("Specular attenuation factor: {}", specular_attenuation_factor_);