目录
- VSCode
- Clion
- CMakeList.txt
VSCode
-
brew install cmake
-
更换下载源为阿里云下载 opencv,不然会很慢
cd "$(brew --repo)" git remote -v cd "$(brew --repo)" git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile source ~/.bash_profile
其中,
git remote -v
表示查看当前下载源 -
brew install opencv
-
用 VSCode 打开作业一文件夹,新建终端
cd ~/GitProjects/GAMES101/Assignment2 mkdir build cd build cmake ../ make
编译成功
现在是这个样子
-
之后不要去管那个 opencv 头文件引用失败,也不要去直接点右上角那个运行的按钮
头文件引用失败是因为 intellisence 工具(用来代码自动填充,文件自动索引)的问题,只要是 CMake 运行成功,那就说明项目配置是正确的,如果要修改,那么需要修改文件 c_cpp_properties.json,具体情况我就不知道了(我没成功)
.
右上角运行按钮需要自己再配置调试运行文件,一般是 C++(GDB/LLDB) ,有个 launch.json 文件,如果使用这种方法,里面的参数需要修改 -
仍然在终端,输入
./Rasterizer
即可运行代码,会有一个弹窗,里面是一条白线,因为你还没与实现投影矩阵函数。 -
你可以先把整个文件的代码替换为下方代码,再执行一遍流程
#include "Triangle.hpp"
#include "rasterizer.hpp"
#include <eigen3/Eigen/Eigen>
#include <iostream>
#include <opencv2/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: Implement this function
// Create the model matrix for rotating the triangle around the Z axis.
// Then return it.
float a = rotation_angle / 180.0 * MY_PI;;
model << cos(a), -sin(a), 0, 0,
sin(a), cos(a), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
return model;
}
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
// Students will implement this function
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
// TODO: Implement this function
// Create the projection matrix for the given parameters.
// Then return it.
// 1. 透视投影转为正交投影矩阵
float n = zNear;
float f = zFar;
Eigen::Matrix4f M_persp2Ortho;
M_persp2Ortho << n, 0, 0, 0,
0, n, 0, 0,
0, 0, n + f, -n * f,
0, 0, 1, 0;
// 2. 正交投影转换到正则立方体
float fov = eye_fov * MY_PI / 180.0;
float t = -n * tan(fov / 2.);
float b = -t;
float r = aspect_ratio * t;
float l = -r;
Eigen::Matrix4f M_ortho, trans, scale;
trans << 1, 0, 0, -(r+l)/2,
0, 1, 0, -(t+b)/2,
0, 0, 1, -(n+f)/2,
0, 0, 0, 1;
scale << 2/(r-l), 0, 0, 0,
0, 2/(t-b), 0, 0,
0, 0, 2/(n-f), 0,
0, 0, 0, 1;
M_ortho = scale * trans;
projection = M_ortho * M_persp2Ortho ;
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]);
}
}
rst::rasterizer r(700, 700);
Eigen::Vector3f eye_pos = {0, 0, 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;
}
看看结果是不是
会发现这个窗口的关闭按钮无法点击,回到 VSCode 的终端,command + c 可以停止(terminate)运行程序,如果是 command + z,挂起(suspend)程序
Clion
直接打开文件夹,之后会提示你选择哪个 CMakeListi.txt 文件,选择项目中的即可,点击运行,出现窗口,点击关闭,结束运行。
CMakeList.txt
cmake_minimum_required(VERSION 3.10)
project(Rasterizer)
find_package(OpenCV REQUIRED)
set(CMAKE_CXX_STANDARD 17)
include_directories(/usr/local/include)
add_executable(Rasterizer main.cpp rasterizer.hpp rasterizer.cpp Triangle.hpp Triangle.cpp)
target_link_libraries(Rasterizer ${OpenCV_LIBRARIES})
这个文件说明这个项目能很好适配linux和mac,看第5行的附加包含目录 /usr/local/include
即可看出
-
project(name) 表示此项目的名字
-
include_directories(/usr/local/include)
相当于附加包含目录,能够直接引用该目录下的头文件,即引用该文件夹下的头文件不会标红线 -
add_executable(Rasterizer main.cpp rasterizer.hpp rasterizer.cpp Triangle.hpp Triangle.cpp)
根据传入的四个参数文件,生成项目的可执行文件 Rasterizer这个指令非常好用,可以让你在一个 project 中运行多个拥有各自 main() 的 .cpp 文件,适合写 io 题
-
两行代码主要是让CMake可以使用 opencv2,因为 opencv2 文件被包含在了 opencv4 文件中,如果不添加这两段代码,直接使用 opencv2,编译器无法找到。
find_package(OpenCV REQUIRED) target_link_libraries(Rasterizer ${OpenCV_LIBRARIES})
(除了这种方法,还可以自己手动添加一个 opencv2 的软链接。但这是没有必要的,因为正常安装下,cmake文件中会自动包含有 opencv4 的软链接,如下图。这个里面包含了很多 .cmake 文件,像 OpenCV_DIR, OpenCV_INCLUDE_DIRS, OpenCV_LIBS 这些变量 cmake 都能自动获取到,只要在 CMakeLists.txt 里加上面两行就能正常使用,此信息来自于文章
https://blog.csdn.net/a13602955218/article/details/101625857
的评论区)