debug phone shading, there are still some problems, may normal related.
This commit is contained in:
parent
635a392a8d
commit
af09ed9311
|
@ -80,7 +80,7 @@ std::vector<Mesh> Mesh::load_mesh(
|
||||||
mesh.MeshMaterial.map_Kd)});
|
mesh.MeshMaterial.map_Kd)});
|
||||||
}
|
}
|
||||||
auto material = std::make_shared<PhoneMaterial>(
|
auto material = std::make_shared<PhoneMaterial>(
|
||||||
textures, std::make_shared<Lamp>(Point3d{}, 192.));
|
textures, std::make_shared<Lamp>(Point3d{}, 16.));
|
||||||
|
|
||||||
res.push_back(Mesh(vertices, primitives, material));
|
res.push_back(Mesh(vertices, primitives, material));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
#include <iostream>
|
||||||
#include <opencv2/highgui/highgui.hpp>
|
#include <opencv2/highgui/highgui.hpp>
|
||||||
|
|
||||||
#include "minus_renderer.h"
|
#include "minus_renderer.h"
|
||||||
|
@ -11,8 +12,7 @@
|
||||||
|
|
||||||
MinusRenderer::MinusRenderer(float near, float far, float fov,
|
MinusRenderer::MinusRenderer(float near, float far, float fov,
|
||||||
float aspect_ratio)
|
float aspect_ratio)
|
||||||
: near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio),
|
: near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio) {
|
||||||
projection_matrix_(orthographic_transform() * squish_transform()) {
|
|
||||||
spdlog::info("near: {}, far: {}, fov: {}, aspect ratio: {}", near_, far_,
|
spdlog::info("near: {}, far: {}, fov: {}, aspect ratio: {}", near_, far_,
|
||||||
fov_, aspect_ratio_);
|
fov_, aspect_ratio_);
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,22 @@ float MinusRenderer::calculate_width(const float height, const float ratio) {
|
||||||
return height * ratio;
|
return height * ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformMatrix MinusRenderer::squish_transform() {
|
std::pair<TransformMatrix, TransformMatrix>
|
||||||
// Frustum to Cuboid
|
MinusRenderer::construct_transform(const int resolution_width,
|
||||||
return TransformMatrix{{near_, 0, 0, 0},
|
const int resolution_height) const {
|
||||||
{0, near_, 0, 0},
|
// Squish Transform
|
||||||
{0, 0, near_ + far_, -near_ * far_},
|
const auto &squish_transform =
|
||||||
{0, 0, 1, 0}};
|
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 height = calculate_height(fov_, near_);
|
||||||
const float width = calculate_width(height, aspect_ratio_);
|
const float width = calculate_width(height, aspect_ratio_);
|
||||||
const float right = width * 0.5;
|
const float right = width * 0.5;
|
||||||
|
@ -47,26 +54,42 @@ TransformMatrix MinusRenderer::orthographic_transform() {
|
||||||
const float top = height * 0.5;
|
const float top = height * 0.5;
|
||||||
const float bottom = -top;
|
const float bottom = -top;
|
||||||
|
|
||||||
TransformMatrix m{{1, 0, 0, -0.5 * (right - left)},
|
const auto &ortho_transform =
|
||||||
{0, 1, 0, -0.5 * (top - bottom)},
|
TransformMatrix{{2 / (right - left), 0, 0, 0},
|
||||||
{0, 0, 1, -0.5 * (far_ - near_)},
|
|
||||||
{0, 0, 0, 1}};
|
|
||||||
|
|
||||||
m = TransformMatrix{{2 / (right - left), 0, 0, 0},
|
|
||||||
{0, 2 / (top - bottom), 0, 0},
|
{0, 2 / (top - bottom), 0, 0},
|
||||||
{0, 0, 2 / std::fabs(far_ - near_), 0},
|
{0, 0, 2 / std::fabs(far_ - near_), 0},
|
||||||
{0, 0, 0, 1}} *
|
{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 auto &ss_transform =
|
||||||
const float height) {
|
view_port_transform * ortho_transform * squish_transform;
|
||||||
return TransformMatrix{{width * 0.5, 0, 0, width * 0.5},
|
const auto &inv_ss_transform =
|
||||||
{0, height * 0.5, 0, height * 0.5},
|
inv_squish_transform * inv_ortho_transform * inv_view_port_transform;
|
||||||
{0, 0, 1, 0},
|
return {ss_transform, inv_ss_transform};
|
||||||
{0, 0, 0, 1}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<double, double, double>
|
std::tuple<double, double, double>
|
||||||
|
@ -106,26 +129,22 @@ void MinusRenderer::view_transform(const TransformMatrix &mtx) {
|
||||||
|
|
||||||
cv::Mat MinusRenderer::render(const int resolution_width,
|
cv::Mat MinusRenderer::render(const int resolution_width,
|
||||||
const int resolution_height) {
|
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<Mesh> meshes = meshes_;
|
std::vector<Mesh> meshes = meshes_;
|
||||||
std::vector<std::vector<double>> perspective_coeff(meshes.size());
|
|
||||||
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 &mesh = meshes[mesh_index];
|
||||||
auto &primitives = mesh.get_primitives();
|
auto &primitives = mesh.get_primitives();
|
||||||
perspective_coeff[mesh_index] =
|
|
||||||
std::vector<double>(mesh.get_vertex_size(), 1.);
|
|
||||||
for (int i = 0; i < primitives.size(); ++i) {
|
for (int i = 0; i < primitives.size(); ++i) {
|
||||||
auto &t = primitives[i];
|
auto &t = primitives[i];
|
||||||
const auto &triangle_vertices = t.get_vertex_position();
|
const auto &triangle_vertices = t.get_vertex_position();
|
||||||
const auto &[projective_res, w] =
|
const auto &[res, _] =
|
||||||
apply_transform(projection_matrix_, triangle_vertices);
|
apply_transform(ss_transform, t.get_vertex_position());
|
||||||
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);
|
|
||||||
t.set_points(res);
|
t.set_points(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,51 +158,57 @@ cv::Mat MinusRenderer::render(const int resolution_width,
|
||||||
color_image.at<cv::Vec3b>(shading_points.size() - y - 1, x);
|
color_image.at<cv::Vec3b>(shading_points.size() - y - 1, x);
|
||||||
pixel_color = cv::Vec3b(0, 0, 0);
|
pixel_color = cv::Vec3b(0, 0, 0);
|
||||||
|
|
||||||
const auto &p = shading_points[y][x];
|
const auto &fragment = shading_points[y][x];
|
||||||
if (p.triangle.mesh_index >= 0 && p.triangle.mesh_index < meshes.size()) {
|
if (fragment.triangle.mesh_index >= 0 &&
|
||||||
const auto &mesh = meshes[p.triangle.mesh_index];
|
fragment.triangle.mesh_index < meshes_.size()) {
|
||||||
|
const auto &mesh = meshes_[fragment.triangle.mesh_index];
|
||||||
const auto &primitives = mesh.get_primitives();
|
const auto &primitives = mesh.get_primitives();
|
||||||
if (p.triangle.triangle_index >= 0 &&
|
if (fragment.triangle.triangle_index >= 0 &&
|
||||||
p.triangle.triangle_index < primitives.size()) {
|
fragment.triangle.triangle_index < primitives.size()) {
|
||||||
const auto &triangle = primitives[p.triangle.triangle_index];
|
const Point3d &position =
|
||||||
const auto &[alpha, beta, gamma] = calculate_barycentric_coordinate(
|
(inv_ss_transform *
|
||||||
triangle, Point2d{x + 0.5, y + 0.5});
|
(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<Point2d> triangle_uv;
|
std::vector<Point2d> triangle_uv;
|
||||||
std::vector<Point3d> triangle_normal;
|
std::vector<Point3d> triangle_normal;
|
||||||
std::vector<double> w_coeff;
|
|
||||||
for (const auto vertex_index : triangle.get_vertex_index()) {
|
for (const auto vertex_index : triangle.get_vertex_index()) {
|
||||||
triangle_uv.push_back(mesh.get_texture_coordinate(vertex_index));
|
triangle_uv.push_back(mesh.get_texture_coordinate(vertex_index));
|
||||||
triangle_normal.push_back(mesh.get_normal_vector(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): 推导一下为什么需要除以下面这个
|
Point2d uv{alpha * triangle_uv[0].x() + beta * triangle_uv[1].x() +
|
||||||
// 在 screen space 对 1/w 的插值就相当于在 world space 对 w 的插值
|
gamma * triangle_uv[2].x(),
|
||||||
auto w_reciprocal = alpha * (1. / w_coeff[0]) +
|
alpha * triangle_uv[0].y() + beta * triangle_uv[1].y() +
|
||||||
beta * (1. / w_coeff[1]) +
|
gamma * triangle_uv[2].y()};
|
||||||
gamma * (1. / w_coeff[2]);
|
spdlog::trace("UV: ({}, {}, {})", uv.x(), uv.y());
|
||||||
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};
|
|
||||||
|
|
||||||
Point3d normal{
|
const auto &normal = Point3d{alpha * triangle_normal[0].x() +
|
||||||
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() + beta * triangle_normal[1].y() +
|
alpha * triangle_normal[0].y() +
|
||||||
gamma * triangle_normal[2].y(),
|
beta * triangle_normal[1].y() +
|
||||||
alpha * triangle_normal[0].z() + beta * triangle_normal[1].z() +
|
gamma * triangle_normal[2].y(),
|
||||||
gamma * triangle_normal[2].z()};
|
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();
|
auto &material = mesh.get_material();
|
||||||
pixel_color = material->shade(
|
pixel_color =
|
||||||
Vertex{Point3d{x, y, p.depth}, normal, uv}, Point3d{});
|
material->shade(Vertex{position, normal, uv}, Point3d{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,13 @@ public:
|
||||||
private:
|
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 TransformMatrix view_port_transform(const float width,
|
|
||||||
const float height);
|
|
||||||
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 Point2d &p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TransformMatrix squish_transform();
|
std::pair<TransformMatrix, TransformMatrix>
|
||||||
TransformMatrix orthographic_transform();
|
construct_transform(const int resolution_width,
|
||||||
|
const int resolution_height) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float near_;
|
float near_;
|
||||||
|
@ -38,7 +37,5 @@ private:
|
||||||
float fov_; // In radian
|
float fov_; // In radian
|
||||||
float aspect_ratio_;
|
float aspect_ratio_;
|
||||||
|
|
||||||
TransformMatrix projection_matrix_;
|
|
||||||
|
|
||||||
std::vector<Mesh> meshes_;
|
std::vector<Mesh> meshes_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ 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{16, 16, 16}),
|
: point_lamp_(lamp), textures_(textures), Ka(cv::Vec3b{32, 32, 32}),
|
||||||
Ks(cv::Vec3b(64, 64, 64)),
|
Ks(cv::Vec3b(64, 64, 64)),
|
||||||
specular_attenuation_factor_(defaultAttenuationFactor) {
|
specular_attenuation_factor_(defaultAttenuationFactor) {
|
||||||
spdlog::info("Specular attenuation factor: {}", specular_attenuation_factor_);
|
spdlog::info("Specular attenuation factor: {}", specular_attenuation_factor_);
|
||||||
|
|
Loading…
Reference in New Issue