跳过正文
  1. Posts/

GAMES101作业1

·974 字·2 分钟·
Xenolies
作者
Xenolies
Keep On Keeping On

全部代码

#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;
}

生成结果: