OpenGL 入门第一课 视窗以及三角形
发布日期:2021-05-04 20:40:33 浏览次数:20 分类:技术文章

本文共 9160 字,大约阅读时间需要 30 分钟。

请查看

下面是我粗劣画的过程图

在这里插入图片描述
下面是课件中的过程图
在这里插入图片描述

在这里插入图片描述

下面是未使用索引缓冲对象(EBO)的

#define GLEW_STATIC // 这个一定要加不然报错 静态链接库#include
#include
#include
using namespace std;void processInput(GLFWwindow);void processInput(GLFWwindow* window) { //如果键盘输入esc 则触发 退出 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { // 设置 要求退出 glfwSetWindowShouldClose(window, true); }}// 逆时针方向绘制 默认情况下,逆时针的顶点连接顺序被定义为三角形的正// 逆时针或顺时针都是相对于观察者方向的float vertices[] = { -0.5f, 0.5f, 0.0f, // 左上角 0.5f, -0.5f, 0.0f, // 右下角 0.5f, 0.5f, 0.0f, // 右上角 // 第二个三角形 0.5f, -0.5f, 0.0f, // 右下角 -0.5f, -0.5f, 0.0f, // 左下角 -0.5f, 0.5f, 0.0f // 左上角};const char* vertexShaderSource ="#version 330 core \n""layout (location = 0) in vec3 aPos; \n""void main() \n""{ \n"" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); \n""} \n";const char* fragmentShaderSource ="#version 330 core \n""out vec4 FragColor; \n""void main() \n""{ \n"" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""} \n";int main() { // 初始化GLFW glfwInit(); // 提示 我们使用的版本是3.3 // 主版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 次版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 简介 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 创建一个窗口对象 GLFWwindow* window = glfwCreateWindow(800, 600, "Test window", NULL, NULL); if (window == NULL) { cout << "open window failed." << endl; // 终止 glfw glfwTerminate(); } // 绑定window到上下文对象 创建完窗口我们就可以通知GLFW将我们窗口的上下文设置为当前线程的主上下文了 glfwMakeContextCurrent(window); glewExperimental = true; // GLEW_OK 0 //init GLEW if (glewInit() != GLEW_OK) { cout << "glew init failed." << endl; // 终止 glfw glfwTerminate(); return -1; } // OpenGL渲染窗口的尺寸大小 // glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素) glViewport(0, 0, 800, 600); // 设置剔除 (opegl默认正面背面都显示(不剔除)) glEnable(GL_CULL_FACE); // 剔除背面 GL_BACK 剔除正面 GL_FRONT glCullFace(GL_BACK); //VAO对象 unsigned int VAO; // 生成一个VAO对象 这个方法可以生成多个 由第一个参数决定 glGenVertexArrays(1, &VAO); // 绑定 VAO glBindVertexArray(VAO); unsigned int VBO; //如果多个可以用 VBO[]数组 这个方法可以生成多个 由第一个参数决定 glGenBuffers(1, &VBO); //将新创建的缓冲绑定到 GL_ARRAY_BUFFER目标上 glBindBuffer(GL_ARRAY_BUFFER, VBO); // glBufferData 是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数 // GL_STATIC_DRAW 数据不会或几乎不会改变。 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 编译着色器 unsigned int vertexShader; // 创建这个着色器 vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // 编译 glCompileShader(vertexShader); // 片段着色器 unsigned int fragmentShader; // 创建这个着色器 fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); // 编译 glCompileShader(fragmentShader); // 着色器程序 是将多个着色器合并之后并最终链接完成的版本 unsigned int shaderProgram; // 创建一个着色器程序对象 shaderProgram = glCreateProgram(); // 将之前编译的着色器附加到程序对象上 glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); // 用glLinkProgram链接它们 glLinkProgram(shaderProgram); // glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据(应用到逐个顶点属性上) // 从 0位 开始 将数据每三个为一组 单位为float 每次跳3*float字节 偏移为0 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 以顶点属性位置值作为参数,启用顶点属性;顶点属性默认是禁用的 glEnableVertexAttribArray(0); //渲染循环 ,它能在我们让GLFW退出前一直保持运行。下面几行的代码就实现了一个简单的渲染循环: //glfwWindowShouldClose 我们每次循环的开始前检查一次GLFW是否被要求退出 while (!glfwWindowShouldClose(window)) { //自定义事件 当键盘触发esc 退出 processInput(window); glClearColor(0.2, 0.3, 0.3, 1.0); // GL_COLOR_BUFFER_BIT 颜色,GL_DEPTH_BUFFER_BIT 深度 和 GL_STENCIL_BUFFER_BIT 模板 // 清除前面的那一帧的颜色 glClear(GL_COLOR_BUFFER_BIT); // 绑定 VAO glBindVertexArray(VAO); glUseProgram(shaderProgram); // 画三角形 从0开始 绘制三个顶点 和VBO的顶点数据(通过VAO间接绑定)来绘制图元 glDrawArrays(GL_TRIANGLES, 0, 6); //解绑VAO glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents(); } // 最后终止 glfw glfwTerminate(); return 0;}

未剔除背面

在这里插入图片描述

剔除背面

在这里插入图片描述

使用EBO的

#define GLEW_STATIC // 这个一定要加不然报错 静态链接库#include
#include
#include
using namespace std;void processInput(GLFWwindow);void processInput(GLFWwindow* window) { //如果键盘输入esc 则触发 退出 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { // 设置 要求退出 glfwSetWindowShouldClose(window, true); }}// 逆时针方向绘制 默认情况下,逆时针的顶点连接顺序被定义为三角形的正// 逆时针或顺时针都是相对于观察者方向的float vertices[] { -0.5f, 0.5f, 0.0f, // 左上角 0 0.5f, -0.5f, 0.0f, // 右下角 1 0.5f, 0.5f, 0.0f, // 右上角 2 // 第二个三角形 //0.5f, -0.5f, 0.0f, // 右下角 -0.5f, -0.5f, 0.0f // 左下角 3 //-0.5f, 0.5f, 0.0f // 左上角};// 使用索引来减小画点的开销 (未用索引缓冲对象时,每个点都需要画一次(即使重复了))unsigned int indices[] { 0,1,2, //第一个三角形的索引 1,3,0 //第二个三角形的索引};const char* vertexShaderSource ="#version 330 core \n""layout (location = 0) in vec3 aPos; \n""void main() \n""{ \n"" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); \n""} \n";const char* fragmentShaderSource ="#version 330 core \n""out vec4 FragColor; \n""void main() \n""{ \n"" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""} \n";int main() { // 初始化GLFW glfwInit(); // 提示 我们使用的版本是3.3 // 主版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 次版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 简介 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 创建一个窗口对象 GLFWwindow* window = glfwCreateWindow(800, 600, "Test window", NULL, NULL); if (window == NULL) { cout << "open window failed." << endl; // 终止 glfw glfwTerminate(); } // 绑定window到上下文对象 创建完窗口我们就可以通知GLFW将我们窗口的上下文设置为当前线程的主上下文了 glfwMakeContextCurrent(window); glewExperimental = true; // GLEW_OK 0 //init GLEW if (glewInit() != GLEW_OK) { cout << "glew init failed." << endl; // 终止 glfw glfwTerminate(); return -1; } // OpenGL渲染窗口的尺寸大小 // glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素) glViewport(0, 0, 800, 600); // 设置剔除 (opegl默认正面背面都显示(不剔除)) glEnable(GL_CULL_FACE); // 剔除背面 GL_BACK 剔除正面 GL_FRONT glCullFace(GL_BACK); //VAO对象 unsigned int VAO; // 生成一个VAO对象 这个方法可以生成多个 由第一个参数决定 glGenVertexArrays(1, &VAO); // 绑定 VAO glBindVertexArray(VAO); unsigned int VBO; //如果多个可以用 VBO[]数组 这个方法可以生成多个 由第一个参数决定 glGenBuffers(1, &VBO); //将新创建的缓冲绑定到 GL_ARRAY_BUFFER目标上 glBindBuffer(GL_ARRAY_BUFFER, VBO); // glBufferData 是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数 // GL_STATIC_DRAW 数据不会或几乎不会改变。 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); unsigned int EBO; glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 编译着色器 unsigned int vertexShader; // 创建这个着色器 vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // 编译 glCompileShader(vertexShader); // 片段着色器 unsigned int fragmentShader; // 创建这个着色器 fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); // 编译 glCompileShader(fragmentShader); // 着色器程序 是将多个着色器合并之后并最终链接完成的版本 unsigned int shaderProgram; // 创建一个着色器程序对象 shaderProgram = glCreateProgram(); // 将之前编译的着色器附加到程序对象上 glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); // 用glLinkProgram链接它们 glLinkProgram(shaderProgram); // glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据(应用到逐个顶点属性上) // 从 0位 开始 将数据每三个为一组 单位为float 每次跳3*float字节 偏移为0 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // 以顶点属性位置值作为参数,启用顶点属性;顶点属性默认是禁用的 glEnableVertexAttribArray(0); //渲染循环 ,它能在我们让GLFW退出前一直保持运行。下面几行的代码就实现了一个简单的渲染循环: //glfwWindowShouldClose 我们每次循环的开始前检查一次GLFW是否被要求退出 while (!glfwWindowShouldClose(window)) { //自定义事件 当键盘触发esc 退出 processInput(window); glClearColor(0.2, 0.3, 0.3, 1.0); // GL_COLOR_BUFFER_BIT 颜色,GL_DEPTH_BUFFER_BIT 深度 和 GL_STENCIL_BUFFER_BIT 模板 // 清除前面的那一帧的颜色 glClear(GL_COLOR_BUFFER_BIT); // 绑定 VAO glBindVertexArray(VAO); glUseProgram(shaderProgram); // 画三角形 从0开始 绘制三个顶点 和VBO的顶点数据(通过VAO间接绑定)来绘制图元 //glDrawArrays(GL_TRIANGLES, 0, 6); 这个是不用索引画的 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//可以不需要这个 绑定VAO的同时也会自动绑定EBO //glDrawElements函数从当前绑定到GL_ELEMENT_ARRAY_BUFFER目标的EBO中获取索引 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); //解绑VAO glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents(); } // 最后终止 glfw glfwTerminate(); return 0;}

使用线框模式

加上下面那行代码就变成线框模式了

glViewport(0, 0, 800, 600);	// 设置剔除 (opegl默认正面背面都显示(不剔除))	glEnable(GL_CULL_FACE);	// 剔除背面 GL_BACK 剔除正面 GL_FRONT	glCullFace(GL_BACK);	// 线框模式 	//第一个参数表示我们打算将其应用到所有的三角形的正面和背面,第二个参数告诉我们用线来绘制	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

效果

在这里插入图片描述
在这里插入图片描述

判断正背面

处理背面剔除有两个需要参考的依据,一个是正背面判断,一个是观察者位置

正背面判断:在OpenGL中默认是逆时针打点的为正面,顺时针为侧面。

上一篇:OpenGL Sharders(着色器) 入门
下一篇:SpringBoot实现国际化

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年03月21日 08时51分01秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

【研究生】PyTorch 1.0稳定版正式发布,并向开发者提供免费AI课程 2019-03-03
平均分392分!某985计算机专硕复试线暴涨! 2019-03-03
为何二战考生成功率远远大于应届? 2019-03-03
计算机专业【本科生】毕业还不如【专科生】? 2019-03-03
考研408联盟新添一所985!某知名大学专业课改用408! 2019-03-03
最有钱的大学是哪个?教育部直属高校公布2018年决算 2019-03-03
408的逆袭!武汉大学所有计算机/软件专业都改为408! 2019-03-03
408又多一所学校!广东某大学专业课改为408! 2019-03-03
【报名问题】考研现场确认时发现报考点选错了怎么办? 2019-03-03
100000+人体验过后都说:这TM绝对是最变态的英语学习方法…… 2019-03-03
广东省将新增一所“中科大”,办学规模初定1万人! 2019-03-03
提醒 | 未下载打印准考证的考生,不能参加2020年考研初试 2019-03-03
【调剂】2020年中科院上海光机所接收报考硕士研究生调剂生的通知 2019-03-03
【调剂】其它计算机/软件调剂信息 20.4.21 2019-03-03
【调剂】211 内蒙古大学计算机学院2020年拟接收调剂硕士研究生公告 2019-03-03
【调剂】浙江理工大学2020年硕士研究生调剂信息 2019-03-03
【调剂】华侨大学媒体分析与数据挖掘小组招收学硕调剂生 2019-03-03
分数线385!平均分399!985大学计算机的真正“实力”! 2019-03-03
【调剂】211云南大学2020年硕士研究生招生调剂通知 2019-03-03
【调剂】985复旦大学类脑智能科学与技术研究院硕士研究生招生接收校内调剂考生工作细则... 2019-03-03