全部代码
#include "Triangle.hpp"
#include "rasterizer.hpp"
#include <cmath>
#include <eigen3/Eigen/Eigen>
#include <iostream>
#include <opencv.hpp>
constexpr double MY_PI = 3.1415926;
// 相机视角矩阵
Eigen::Matrix4f get_view_matrix(Eigen::Vector3f eye_pos) {
Eigen::Matrix4f view = Eigen::Matrix4f::Identity();
Eigen::Matrix4f translate;
translate << 1, 0, 0, -eye_pos[0], 0, 1, 0, -eye_pos[1], 0, 0, 1, -eye_pos[2],
0, 0, 0, 1; // 齐次坐标
view = translate * view;
return view;
}
//模型矩阵 参数是一个旋转的角度
Eigen::Matrix4f get_model_matrix(float rotation_angle) {
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
// TODO: 实现此函数
// 创建绕 Z 轴旋转三角形的模型矩阵。
// 然后返回该矩阵。
float rad = rotation_angle * (MY_PI / 180);
Eigen::Matrix4f rotation;
// 旋转矩阵中numext::sin的三角函数接收的是弧度需要将角度转为弧度:弧度=角度*(PI/180)
rotation << numext::cos(rad), -numext::sin(rad), 0, 0, // 第一行
numext::sin(rad), numext::cos(rad), 0, 0, // 第二行
0, 0, 1, 0, //第三行
0, 0, 0, 1;
model = rotation * model;
return model;
}
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar) {
// 学生将实现此函数
// 已知条件: 视角 eye_fov 宽高比 aspect_ratio ,z近点 zNear z远点 zFar
// 思路 因为垂直方向半高 t = |z| * tan(fov/2) 所以可以得到半高t ,
// 已知宽高比aspect_ratio和半高 t 可以得到水平方向半宽r = t * aspect_ratio
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
// 前面求出来t和r ,将其映射到一个[-1,1]3的坐标系中,可得出:
// 左面 l = -r , 右面 r = r
// 顶面 t = t , 地面 b = -t
// 近平面 n = zNear ,远平面 f = zFar
// 由于相机是从-z方向看过去的(n>f),所以n需要取负号
// 可以写出正交投影矩阵 ortho
float l, b, n, f;
n = zNear;
f = zFar;
float rad = eye_fov * (MY_PI / 180.0);
float t = -abs(n) * numext::tan(rad / 2);
// 水平方向半宽 r
float r = t * aspect_ratio;
l = -r;
b = -t;
// 输出 l, r, t, b, n, f 的值
std::cout << "投影矩阵参数:" << std::endl;
std::cout << "l = " << l << ", r = " << r << std::endl;
std::cout << "t = " << t << ", b = " << b << std::endl;
std::cout << "n = " << n << ", f = " << f << std::endl;
// 正交投影矩阵 ortho = 旋转矩阵 scale * 平移矩阵 translation
Eigen::Matrix4f scale; // 旋转矩阵 scale
scale << 2 / (r - l), 0, 0, 0, // 1
0, 2 / (t - b), 0, 0, // 2
0, 0, 2 / (n - f), 0, // 3
0, 0, 0, 1;
Eigen::Matrix4f translation;
translation << 1, 0, 0, -(l + r) / 2, // 1
0, 1, 0, -(t + b) / 2, // 2
0, 0, 1, -(n + f) / 2, // 3
0, 0, 0, 1;
// 正交投影矩阵 ortho = 旋转矩阵 scale * 平移矩阵 translation
Eigen::Matrix4f ortho = scale * translation;
//投影变换矩阵 persp_to_ortho
Eigen::Matrix4f persp_to_ortho;
persp_to_ortho << n, 0, 0, 0, // 1
0, n, 0, 0, // 2
0, 0, n + f, -(n * f), // 3
0, 0, 1, 0;
projection = ortho * persp_to_ortho;
// TODO: 实现此函数
// 根据给定参数创建投影矩阵。
// 然后返回该矩阵。
return projection;
}
int main(int argc, const char **argv) {
float angle = 0;
bool command_line = false;
std::string filename = "output.png";
if (argc >= 3) {
command_line = true;
angle = std::stof(argv[2]); // -r by default
if (argc == 4) {
filename = std::string(argv[3]);
} else
return 0;
}
rst::rasterizer r(700, 700);
Eigen::Vector3f eye_pos = {0, 0, 5}; // 相机视角z轴距离 5
std::vector<Eigen::Vector3f> pos{{2, 0, -2}, {0, 2, -2}, {-2, 0, -2}};
std::vector<Eigen::Vector3i> ind{{0, 1, 2}};
auto pos_id = r.load_positions(pos);
auto ind_id = r.load_indices(ind);
int key = 0;
int frame_count = 0;
if (command_line) {
r.clear(rst::Buffers::Color | rst::Buffers::Depth);
r.set_model(get_model_matrix(angle));
r.set_view(get_view_matrix(eye_pos));
r.set_projection(get_projection_matrix(45, 1, 0.1, 50));
r.draw(pos_id, ind_id, rst::Primitive::Triangle);
cv::Mat image(700, 700, CV_32FC3, r.frame_buffer().data());
image.convertTo(image, CV_8UC3, 1.0f);
cv::imwrite(filename, image);
return 0;
}
while (key != 27) {
r.clear(rst::Buffers::Color | rst::Buffers::Depth);
r.set_model(get_model_matrix(angle));
r.set_view(get_view_matrix(eye_pos));
r.set_projection(get_projection_matrix(45, 1, 0.1, 50));
r.draw(pos_id, ind_id, rst::Primitive::Triangle);
cv::Mat image(700, 700, CV_32FC3, r.frame_buffer().data());
image.convertTo(image, CV_8UC3, 1.0f);
cv::imshow("image", image);
key = cv::waitKey(10);
std::cout << "frame count: " << frame_count++ << '\n';
if (key == 'a') {
angle += 10;
} else if (key == 'd') {
angle -= 10;
}
}
return 0;
}生成结果:

