依然是用windows+vs2019完成作业
新的安装与配置:
安装与配置openCV计算机视觉库:
https://blog.csdn.net/maizousidemao/article/details/81474834
挨着扔进去
遇到的问题:
1.error LNK1112: 模块计算机类型“X86”与目标计算机类型“x64”冲突
解决办法:解决方案使用debug x64,如果之前是x86,要全部重新配置一下
(以下错误建立在我把基础配置的库文件名给添加反了(错误添加为opencv_world455.lib而不是opencv_world455d.lib),遇到的一系列错误。)
2.错误 LNK2019 无法解析的外部符号 “public: void __cdecl cv::Mat::copyTo(class cv::debug_build_guard::_OutputArray
解决办法:https://blog.csdn.net/goethe/article/details/111032728
3.Microsoft C++ 异常: std::bad_alloc。大概就是空间溢出,报错的函数是:imshow(“image”, image);
解决办法:。。。好吧最后都没解决。。最后意识到自己的错误了,把配置的最后一步写错了,忘了给库文件名加上d,除此之外还需要把上一步添加的宏定义:CV_IGNORE_DEBUG_BUILD_GUARD 给删除。不删除这个的话,只改掉库文件名依然会报错。
作业分析
认真阅读了作业文档后,一直在纠结自己到底要写哪一个部分,看了很久不知道要rasterizer需要写什么,最后发现,是需要理解rasterizer.hpp和修改main.cpp。。。
更具体的话,是只需要自己写main函数当中的 Matrix4f get_model_matrix(float rotation_angle) 还有 Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,float zNear, float zFar) 。
如果什么都不写的话,直接运行出来会显示出一根直线:
代码部分
尽自己可能理解一下
#include "Triangle.hpp"
#include "rasterizer.hpp"
#include <Eigen/Eigen>
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace Eigen;
using namespace cv;
constexpr double MY_PI = 3.1415926;
//矩阵平移,上一个作业内容
Matrix4f get_view_matrix(Vector3f eye_pos)
{
Matrix4f view = Matrix4f::Identity();
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;
}
//矩阵绕z轴旋转,传入参数是旋转角度
//本次需要填写的内容
Matrix4f get_model_matrix(float rotation_angle)
{
Matrix4f model = Matrix4f::Identity();
//视频里面的成品公式直接代入
Matrix4f rotation;
float rot = rotation_angle * MY_PI / 180.0;
rotation << cos(rot), -sin(rot), 0, 0,
sin(rot), cos(rot), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
model = rotation * model;
return model;
}
//透视投影,根据名字判断,4个参数分别是:上下可视角度,长宽比width / height,z近距离,z远距离(分别为视频5,5,4,4提到的内容)
//本次需要填写的内容
Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
Matrix4f projection = Matrix4f::Identity();
//其实也是视频里面成品公式直接代入,只不过需要理解怎么把上面给的参数给转换成我们需要的数据
Matrix4f persp;
Matrix4f ortho1,ortho2;
float r, l, t, b, n, f;//视频里面老师举例子一模一样的参数,可以根据视频挨个对应
float angle = eye_fov * MY_PI / 180.0 / 2;//只看上半部分,已经除以2
n = zNear;
f = zFar;
t = -tan(angle) * n;
b = tan(angle) * n;
r = t * aspect_ratio;
l = -t * aspect_ratio;
persp << n, 0, 0, 0,//视频4最后的那道题的结果
0, n, 0, 0,
0, 0, n+f, -n*f,
0, 0, 1, 0;
ortho1 << 2 / (r - l), 0, 0, 0,
0, 2 / (t - b), 0, 0,
0, 0, 2 / (n - f), 0,
0, 0, 0, 1;
ortho2 << 1, 0, 0, -(r + l) / 2,
0, 1, 0, -(t + b) / 2,
0, 0, 1, -(n + f) / 2,
0, 0, 0, 1;
projection = ortho1 * ortho2 * persp * projection;
return projection;
}
int main(int argc, const char** argv)
{
float angle = 0;
//使用命令行的方法来控制,这时候会保存到指定位置,注释了来区分一下两种输入方法
// bool command_line = false;
// string filename = "output.png";
// if (argc >= 3) {
// command_line = true;
// angle = stof(argv[2]); // -r by default
// if (argc == 4) {
// filename = string(argv[3]);
// }
// }
rst::rasterizer r(700, 700);
Vector3f eye_pos = {0, 0, 5};
vector<Vector3f> pos{{2, 0, -2}, {0, 2, -2}, {-2, 0, -2}};
vector<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);
// Mat image(700,700, CV_32FC3, r.frame_buffer().data());
// image.convertTo(image, CV_8UC3, 1.0f);
// imwrite(filename, image);
// return 0;
//}
while (key != 27) {//运行后输入esc退出
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);
Mat image(700, 700, CV_32FC3, r.frame_buffer().data());
image.convertTo(image, CV_8UC3, 1.0f);//图像的各种参数
imshow("image", image);//显示图像
key = waitKey(10);//每次等待一小段时间再刷新图片
cout << "frame count: " << frame_count++ << '\n';//while循环次数统计
if (key == 'a') {//输入a,角度+10
angle += 10;
}
else if (key == 'd') {//输入b,角度-10
angle -= 10;
}
}
return 0;
}
运行结果
初始,以及按了两次a后的结果
疑问:
做的时候有个问题就是,按照这个参数给的方法,其实已经限定了透视投影的那个图形是一个在z的负轴上,对于x轴上下对称,y轴左右对称的一个图形。其实很不能理解为什么可以默认这样,为什么不能在其他位置呢。