【计算机图形学】2三维模型读取与控制-C++文档类资源-CSDN文库
目的与要求:
- 熟悉OpenGL 三维模型的读取与处理;理解三维模型的基本变换操作;掌握鼠标键盘交互控制逻辑;掌握着色器中uniform关键字的使用以及数据传输方法。
- OFF格式三维模型文件的读取:完成对OFF格式三维模型文件的读取与显示,可改变物体的显示颜色。
/*main.cpp*/ #include "Angel.h" #include <vector> #include <string> #include <fstream> #include <string> // #pragma comment(lib, "glew32.lib") // 三角面片中的顶点序列 typedef struct vIndex { unsigned int a, b, c; vIndex(int ia, int ib, int ic) : a(ia), b(ib), c(ic) {} } vec3i; std::string filename; std::vector<vec3i> faces; int nVertices = 0; int nFaces = 0; int nEdges = 0; int Automatic_rotation = 0; const int X_AXIS = 0; const int Y_AXIS = 1; const int Z_AXIS = 2; const int ANIMATION_START = 0; const int ANIMATION_STOP = 1; const int ANIMATION_AXIS = 2; const int TRANSFORM_SCALE = 5; const int TRANSFORM_ROTATE = 6; const int TRANSFORM_TRANSLATE = 7; const int SHOW_STATUS = 8; const int RESET = 9; int rotateAxis = Y_AXIS; // 旋转轴,默认为y轴 const double DELTA_DELTA = 0.1; // Delta的变化率 const double DEFAULT_DELTA = 0.3; // 默认的Delta值 double scaleDelta = DEFAULT_DELTA; double rotateDelta = DEFAULT_DELTA; double translateDelta = DEFAULT_DELTA; glm::vec3 scaleTheta(1.0, 1.0, 1.0); // 缩放控制变量 glm::vec3 rotateTheta(0.0, 0.0, 0.0); // 旋转控制变量 glm::vec3 translateTheta(0.0, 0.0, 0.0); // 平移控制变量 GLint matrixLocation; int currentTransform = TRANSFORM_TRANSLATE; // 设置当前变换 int mainWindow; // 模型中的各个点 // const int NUM_VERTICES = 8; const int NUM_VERTICES = 2904; glm::vec3 vertices[NUM_VERTICES]; void read_off(const std::string filename) { if (filename.empty()) { return; } std::ifstream fin; fin.open(filename); TODO: 完成对OFF格式三维模型文件的读取: fin.close(); } void init() { // 创建顶点数组对象 GLuint vao[1]; #ifdef __APPLE__ // for MacOS glGenVertexArraysAPPLE(1, vao); glBindVertexArrayAPPLE(vao[0]); #else // for Windows glGenVertexArrays(1, vao); glBindVertexArray(vao[0]); #endif // 创建并初始化顶点缓存对象 GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, nVertices * sizeof(glm::vec3), vertices, GL_STATIC_DRAW); // 创建并初始化顶点索引缓存对象 GLuint vertexIndexBuffer; glGenBuffers(1, &vertexIndexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexIndexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.size() * sizeof(vec3i), faces.data(), GL_STATIC_DRAW); // 读取着色器并使用 std::string vshader, fshader; #ifdef __APPLE__ // for MacOS vshader = "shaders/vshader_mac.glsl"; fshader = "shaders/fshader_mac.glsl"; #else // for Windows vshader = "shaders/vshader_win.glsl"; fshader = "shaders/fshader_win.glsl"; #endif GLuint program = InitShader(vshader.c_str(), fshader.c_str()); glUseProgram(program); // 从顶点着色器中初始化顶点的位置 GLuint pLocation = glGetAttribLocation(program, "vPosition"); glEnableVertexAttribArray(pLocation); glVertexAttribPointer(pLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); /// /TODO: 获取变换矩阵的存储位置,并保存到matrixLocation: // 黑色背景 glClearColor(0, 0, 0, 0); } void display() { // 清理窗口 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 生成变换矩阵 glm::mat4 m(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); TODO: 计算变换矩阵: TODO: 从指定位置matrixLocation中传入变换矩阵: // 绘制图形中的各个三角形 glDrawElements(GL_TRIANGLES, int(faces.size() * 3), GL_UNSIGNED_INT, BUFFER_OFFSET(0)); } // 根据Delta值更新Theta void updateTheta(int axis, int sign) { switch (currentTransform) { case TRANSFORM_SCALE: scaleTheta[axis] += sign * scaleDelta; break; case TRANSFORM_ROTATE: rotateTheta[axis] += sign * rotateDelta; break; case TRANSFORM_TRANSLATE: translateTheta[axis] += sign * translateDelta; break; } } // 复原Theta和Delta void resetTheta() { scaleTheta = glm::vec3(1.0, 1.0, 1.0); rotateTheta = glm::vec3(0.0, 0.0, 0.0); translateTheta = glm::vec3(0.0, 0.0, 0.0); scaleDelta = DEFAULT_DELTA; rotateDelta = DEFAULT_DELTA; translateDelta = DEFAULT_DELTA; } // 更新变化Delta值 void updateDelta(int sign) { switch (currentTransform) { case TRANSFORM_SCALE: scaleDelta += sign * DELTA_DELTA; break; case TRANSFORM_ROTATE: rotateDelta += sign * DELTA_DELTA; break; case TRANSFORM_TRANSLATE: translateDelta += sign * DELTA_DELTA; break; } } // 键盘操作函数 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { float tmp; glm::vec4 ambient; if (action == GLFW_PRESS) { switch (key) { case GLFW_KEY_ESCAPE: exit(EXIT_SUCCESS); break; // 手动旋转 case GLFW_KEY_Q: updateTheta(X_AXIS, 1); break; case GLFW_KEY_A: updateTheta(X_AXIS, -1); break; case GLFW_KEY_W: updateTheta(Y_AXIS, 1); break; case GLFW_KEY_S: updateTheta(Y_AXIS, -1); break; case GLFW_KEY_E: updateTheta(Z_AXIS, 1); break; case GLFW_KEY_D: updateTheta(Z_AXIS, -1); break; // 设置旋转度数 case GLFW_KEY_R: updateDelta(1); break; case GLFW_KEY_F: updateDelta(-1); break; case GLFW_KEY_T: resetTheta(); break; TODO: 添加代码完成键盘自动旋转动画的旋转轴选取: break; } } } //TODO: 修改mouse_button_callback函数,完成鼠标控制旋转的开始与停止: void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { } void prinfStatus() { printf("\nCurrent Status:\n"); switch (currentTransform) { case TRANSFORM_SCALE: printf(" Current Transform: Scale\n"); printf(" scaleTheta: (%.2f, %.2f, %.2f)\n", scaleTheta.x, scaleTheta.y, scaleTheta.z); printf(" scaleDelta: %.2f\n", scaleDelta); break; case TRANSFORM_ROTATE: printf(" Current Transform: Rotate\n"); printf(" rotateTheta: (%.2f, %.2f, %.2f)\n", rotateTheta.x, rotateTheta.y, rotateTheta.z); printf(" rotateDelta: %.2f\n", rotateDelta); break; case TRANSFORM_TRANSLATE: printf(" Current Transform: Translate\n"); printf(" translateTheta: (%.2f, %.2f, %.2f)\n", translateTheta.x, translateTheta.y, translateTheta.z); printf(" translateDelta: %.2f\n", translateDelta); break; } } void printHelp() { printf("Mouse options:\n"); printf(" Left Button: Start Animation\n"); printf(" Right Button: Stop Animation\n"); printf("\n\n"); printf("Keyboard options:\n"); printf(" Esc: Exit Program\n"); printf(" R: Increase delta of currently selected transform\n"); printf(" F: Decrease delta of currently selected transform\n"); printf(" T: Reset all transformations and deltas\n"); printf(" - While in animation\n"); printf(" Z: Set Z Axis as the rotation axis\n"); printf(" X: Set X Axis as the rotation axis\n"); printf(" C: Set Y Axis as the rotation axis\n"); printf(" - While not in animation\n"); printf(" Q: Increase x\n"); printf(" A: Decrease x\n"); printf(" W: Increase y\n"); printf(" S: Decrease y\n"); printf(" E: Increase z\n"); printf(" D: Decrease z\n"); } void framebuffer_size_callback(GLFWwindow* window, int width, int height); int main(int argc, char **argv) { // 初始化GLFW库,必须是应用程序调用的第一个GLFW函数 glfwInit(); // 配置GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif // 配置窗口属性 GLFWwindow* window = glfwCreateWindow(600, 600, "学号_姓名_作业二", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // 调用任何OpenGL的函数之前初始化GLAD // --------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // 读入OFF // read_off("cube.off"); // 读取立方体 read_off("cow.off"); // 读取牛模型 // Init mesh, shaders, buffer init(); // 输出帮助信息 printHelp(); // 启用深度测试 glEnable(GL_DEPTH_TEST); while (!glfwWindowShouldClose(window)) { if (Automatic_rotation == 1) updateTheta(rotateAxis, 1); display(); //reshape(); // 交换颜色缓冲 以及 检查有没有触发什么事件(比如键盘输入、鼠标移动等) // ------------------------------------------------------------------------------- glfwSwapBuffers(window); glfwPollEvents(); } return 0; } // 每当窗口改变大小,GLFW会调用这个函数并填充相应的参数供你处理。 // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); }
- 内容
提供的off格式三维模型,并对其赋色。利用鼠标和键盘的交互,控制动画效果,模型的颜色自己可以自行设置,好看就行。
/*@author:2019274072许佳妮(代码添加修改均价上【jennie】)
* 本工程基本功能是基于cow.off文件,进行绘制上色并实现360度自动旋转,具体实现功能如下:(以下展示工程里【行号】)
* 1.读取off文件并上色,显示奶牛
* 1.1 定义着色器绘制点和颜色、不同颜色【95-109】
* 1.2 Read_off()函数读文件【122-175】
*/
- 具体内容
- OFF格式三维模型文件的读取
参考上机实验2.2的内容,完成对OFF格式三维模型文件的读取与显示,可改变物体的显示颜色,尽量特别,但不要太难看。
-
- 定义着色器绘制点和颜色、不同颜色
std::vector<glm::vec3> points; // 传入着色器的绘制点【jennie(读off 1.1)】 std::vector<glm::vec3> colors; // 传入着色器的颜色【jennie(读off 1.1)】 const int COLOR_NUM_VERTICES = 8; //颜色数【jennie(读off 1.1)】 //色种【jennie(读off 1.1)】 const glm::vec3 vertex_colors[COLOR_NUM_VERTICES] = { glm::vec3(1.0, 1.0, 1.0), // White glm::vec3(1.0, 1.0, 0.0), // Yellow glm::vec3(0.0, 1.0, 0.0), // Green glm::vec3(0.0, 1.0, 1.0), // Cyan glm::vec3(1.0, 0.0, 1.0), // Magenta glm::vec3(1.0, 0.0, 0.0), // Red glm::vec3(0.0, 0.0, 0.0), // Black glm::vec3(0.0, 0.0, 1.0) // Blue };
- 定义着色器绘制点和颜色、不同颜色
- 2 Read_off()函数读文件(图表 1)
根据off的文件格式,依次读入顶点信息和片元信息存入顶点数组vertices[]和片元数组faces[],在整理二者的数据存入points,同时填色。
void read_off(const std::string filename)
{
if (filename.empty()) {
return;
}
std::ifstream fin;
fin.open(filename);
TODO: 完成对OFF格式三维模型文件的读取:
if (!fin)
{
printf("文件有误\n");
return;
}
else
{
printf("文件打开成功\n");
for (int i = 0; i < NUM_VERTICES; i++) {
vertices[i] = glm::vec3(0.0f); //清空顶点数组
}
faces.clear();
// 读取OFF字符串
std::string str;
fin >> str;
// 读取文件中顶点数、面片数、边数
fin >> nVertices >> nFaces >> nEdges;
// 根据顶点数,循环读取每个顶点坐标,将其保存到vertices
float x, y, z;
for (int i = 0; i < nVertices; i++) {
fin >> x >> y >> z;
vertices[i]=glm::vec3(x, y, z);
}
// 根据面片数,循环读取每个面片信息,并用构建的vec3i结构体保存到faces
unsigned int n, a, b, c;
for (int i = 0; i < nFaces; i++) {
fin >> n >> a >> b >> c;
faces.push_back(vec3i(a, b, c));
}
points.clear();
colors.clear();
// @TODO: Task1:修改此函数在points和colors容器中存储每个三角面片的各个点和颜色信息
// 在points容器中,依次添加每个面片的顶点,并在colors容器中,添加该点的颜色信息
// 比如一个正方形由两个三角形构成,那么vertices会由4个顶点的数据构成,faces会记录两个三角形的顶点下标,
// 而points就是记录这2个三角形的顶点,总共6个顶点的数据。
// colors容器则是和points的顶点一一对应,保存这个顶点的颜色,这里我们可以使用顶点坐标或者自己设定的颜色赋值。
for (int i = 0; i < nFaces; i++) {
points.push_back(vertices[faces[i].a]);
points.push_back(vertices[faces[i].b]);
points.push_back(vertices[faces[i].c]);
/*//单色
for (int j = 0; j < 3; j++) {
colors.push_back(vertex_colors[i / 2]);
}*/
colors.push_back(vertex_colors[faces[i].a]);
colors.push_back(vertex_colors[faces[i].b]);
colors.push_back(vertex_colors[faces[i].c]);
}
}
fin.close();
}