OpenGL环境配置及着色器工作流
OpenGL相关笔记
最近在看图像后处理相关代码,学了一段时间的opengl,下面是从思维导图笔记转化过来的文档
学习的相关知识来源于 [https://learnopengl-cn.github.io/intro/]
一、环境配置和相关概念
1.1 环境配置
vs2019+nuget
nuget 安装 glfw glew-c++
可能遇到的问题:__imp__glClear@4,该符号在函数 _main 中被引用
原因:未引入依赖项opengl32.lib
解决方法:版本、平台、附加依赖项opengl32.lib
1.2 包相关知识
OpenGL utility library 标准GLU 头文件 gl.h glu.h
OpenGL utility toolkit 工具箱GLUT 头文件 glut.h
区别:
glew(The OpenGL Extension Wrangler Library)是对底层OpenGL接口的封装,可以让你的代码跨平台。
GLEW是用来管理OpenGL的函数指针的
glad与glew作用相同,可以看作它的升级版。
glew.h
不同的显卡公司,也会发布一些只有自家显卡才支 持的扩展函数,你要想用这数涵数,不得不去寻找最新的glext.h,有了GLEW扩展库,你就再也不用为找不到函数的接口而烦恼,因为GLEW能自动识别你的平台所支持的全部OpenGL高级扩展函数。也就是说,只要包含一个glew.h头文件,你就能使用gl,glu,glext,wgl,glx的全部函数。
glfw.h
一个轻量级的,开源的,跨平台的library。支持OpenGL及OpenGL ES,用来管理窗口,读取输入,处理事件等。因为OpenGL没有窗口管理的功能,所以很多热心的人写了工具来支持这些功能,比如早期的glut,现在的freeglut等。那么GLFW有何优势呢?glut太老了,最后一个版本还是90年代的。freeglut完全兼容glut,算是glut的代替品,功能齐全,但是bug太多。稳定性也不好(不是我说的啊),GLFW应运而生。
1.3 基础概念
1.3.1 着色
-
名词
-
管线:将3D坐标转换为2D坐标,然后将2D坐标转换Wie2D像素输出
-
顶点数组对象:Vertex Array Object,VAO
- 在VAO后创建的VBO都属于该VAO。关联VBO数据用取得当前激活的缓存区对象偏移来指定。
- VAO是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用
-
顶点缓冲对象:Vertex Buffer Object,VBO
- 优点:采用VBO、VAO节省了绘制多个物体时 CPU 与 GPU 之间的通讯时间,提高了渲染性能。
- VBO是内存缓冲区,用来保存顶点信息,颜色信息,法线信息,纹理坐标信息和索引信息等等
-
Uniform
- 从CPU中的应用向GPU中的着色器发送数据的方式
- 全局变量,以被着色器程序的任意着色器在任意阶段访问
-
-
着色器运行在GPU上,存在每个渲染管线阶段
-
OpenGL 着色器是用 OpenGL 着色器语言 (OpenGL Shading Language 即 GLSL)
-
GLSL中的向量是一个可以包含有1、2、3或者4个分量的容器,分量的类型可以是前面默认基础类型的任意一个
cnblog参考
1.3.2 着色器代码特点
- 着色器的开头总是要声明版本,接着是输入和输出变量、uniform(以后会解释)和main函数
1.3.3 layout
- 顶点在内存的布局
- layout(location=0) 代表元素排列在顶点数据内存为0位置
二、顶点数据(缓冲)的创建及属性配置
2.1 VBO
-
VBO创建
-
生成缓冲区对象
- glGenBuffers(1, &VBO)
-
- 绑定顶点信息
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
-
- 数据传输
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
-
-
删除
- glDeleteBuffers(1, &VBO);
-
解除绑定
- glBindBuffer(GL_ARRAY_BUFFER, 0)
2.2 VAO
-
VAO创建
-
- 生成VAO对象
- glGenVertexArrays(1, &VAO);
-
- 绑定VAO
- glBindVertexArray(VAO);
- 执行VAO绑定之后其后的所有VBO配置都是这个VAO对象的一部分,可以说VBO是对顶点属性信息的绑定,VAO是对很多个VBO的绑定。
-
-
删除
- glDeleteVertexArrays(1, &VAO);
-
解除绑定
- glBindVertexArray(0)
配置VAO和VBO
-
- 解释顶点数据,设置顶点属性指针
- glVertexAttribPointer
-
- 启用顶点数据
- glEnableVertexAttribArray
2.3 EBO
-
VBO创建
-
生成缓冲区对象
- glGenBuffers(1, &EBO);
-
- 绑定顶点信息
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
-
- 数据传输
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
-
-
删除
- glDeleteBuffers(1, &VBO);
-
解除绑定
- glBindBuffer(GL_ARRAY_BUFFER, 0)
注意点
当目标是GL_ELEMENT_ARRAY_BUFFER的时候,VAO会储存glBindBuffer的函数调用。这也意味着它也会储存解绑调用,所以确保你没有在解绑VAO之前解绑索引数组缓冲,否则它就没有这个EBO配置了
三、着色器工作流
3.1 着色器对象创建及编译
-
顶点着色器
- glCreateShader ( GL_VERTEX_SHADER )
- glShaderSource
- glCompileShader ( vertexShader );
- glGetShaderiv ( vertexShader, GL_COMPILE_STATUS, &success );
-
片段着色器
-
顶点着色器
-
创建着色器
- glCreateShader ( GL_VERTEX_SHADER )
-
glShaderSource
-
glCompileShader ( vertexShader );
-
glGetShaderiv ( vertexShader, GL_COMPILE_STATUS, &success );
-
3.2 链接着色器对象到用来渲染的着色器程序中
- glLinkProgram(shaderProgram);
3.3 程序调用
- glUseProgram(shaderProgram);
四、绘制工作流
4.1 使用当前的激活的着色器
- glUseProgram(shaderProgram);
4.2 绑定相应的VAO
- glBindVertexArray(VAO);
4.3 绘制物体
- glDrawArrays(GL_TRIANGLES, 0, 3);
4.4 解绑VAO
思路:它使用当前激活的着色器,之前定义的顶点属性配置,和VBO的顶点数据(通过VAO间接绑定)来绘制图元。
五、纹理工作流(未完成)
glTexParameteri
-
作用:确定如何把纹理象素映射成像素,因为图象从纹理图象空间映射到帧缓冲图象空间(映射需要重新构造纹理图像,这样就会造成应用到多边形上的图像失真)
-
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
参数:1.指定纹理目标类型 2.指定设置的选项与应用的纹理轴 3.递一个环绕方式(Wrapping)
-
纹理类型
- GL_TEXTURE_2D
- GL_TEXTURE_3D
-
设置选项
-
STR方向上的贴图模式
-
应用的纹理轴S、T、R:类似x、y、z
-
GL_TEXTURE_WRAP_S: S方向上的贴图模式
-
环绕Wrapping
- GL_REPEAT :对纹理的默认行为。重复纹理图像。
- GL_MIRRORED_REPEAT :和GL_REPEAT一样,但每次重复图片是镜像放置的。
- GL_CLAMP_TO_EDGE :纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
- GL_CLAMP_TO_BORDER:超出的坐标为用户指定的边缘颜色。
-
-
纹理过滤
-
GL_TEXTURE_MAG_FILTER: 放大过滤
-
GL_TEXTURE_MIN_FILTER: 缩小过滤
-
过滤方式
- GL_LINEAR: 线性过滤
- GL_LINEAR_MIPMAP_NEAREST: 邻近过滤
-
-
-
多级过滤
-
glBindTexture
- 绑定纹理
- glBindTexture(GL_TEXTURE_3D, pTexture->GetTextureName());
glGenerateMipmap
glTexImage2D
glGenTextures
- 生成纹理
- glGenTextures(1, &texture);
glActiveTexture
纹理坐标
- 纹理坐标是你给模型顶点设置的那个数组,OpenGL以这个顶点的纹理坐标数据去查找纹理图像上的像素,然后进行采样提取纹理像素的颜色。
- 纹理坐标范围为0到1之间,纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角
- 每个顶点就会关联着一个纹理坐标,用来标明该从纹理图像的哪个部分采样
六、附录-常用函数
顶点数据
-
glBufferData
- 调用glBufferData函数,把之前定义的顶点数据复制到显存缓冲区中
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
-
glBindBuffer
-
把新创建的缓冲绑定到指定类型上,参数:缓冲类型、缓冲ID
-
目标缓存类型
- GL_ARRAY_BUFFER
- GL_ELEMENT_ARRAY_BUFFER
-
-
glEnableVertexAttribArray
- 允许顶点着色器读取GPU(服务器端)数据:数据在GPU端是否可见,即,着色器能否读取到数据,由是否启用了对应的属性决定
- 与其他区别。glVertexAttribPointer或VBO只是建立CPU和GPU之间的逻辑连接,从而实现了CPU数据上传至GPU
-
glVertexAttribPointer
-
参数:1.位置 2.大小 3.数据类型 4.标准化 5.步长 6.偏移量
计算步长值。为获得数据队列中下一个属性值:3个是位置值,另外3个是颜色值。这使我们的步长值为6乘以float的字节数
计算偏移量:如颜色值3个float
-
指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置。它们之间也是通过上下文,只有唯一的激活VAO,在VAO后创建的VBO都属于该VAO。关联VBO数据用取得当前激活的缓存区对象偏移来指定。
-
-
glBufferData
-
作用:用来把用户定义的数据复制到当前绑定缓冲的函数
-
参数:1是目标缓冲的类型 2.指定传输数据的大小 3.发送的实际数据 4.显卡如何管理给定数据
-
目标缓存类型
- GL_ARRAY_BUFFER
- GL_ELEMENT_ARRAY_BUFFER
-
显卡如何管理给定的数据
- GL_STATIC_DRAW :数据不会或几乎不会改变。
- GL_DYNAMIC_DRAW:数据会被改变很多。
- GL_STREAM_DRAW :数据每次绘制时都会改变。
-
-
glGenBuffers
- void glGenBuffers(GLsizei n,GLuint * buffers);
- 第一个参数是要生成的缓冲对象的数量,第二个是要输入用来存储缓冲对象名称的数组
该函数会在buffers里返回n个缓冲对象的名称。
-
glBindVertexArray
glUniform4f
- 设置uniform值:无返回
- glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
glUseProgram
- 调用程序:无返回
- glUseProgram(shaderProgram);
glGetUniformLocation
- 查询uniform ourColor的位置值:返回位置值,-1代表未查询到
- int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
着色器对象和程序
-
glCreateShader
-
创建一个着色器对象,并返回着色器对象ID引用
-
类型
- GL_VERTEX_SHADER
- GL_FRAGMENT_SHADER
-
-
glCompileShader
- 编译着色器对象
- glCompileShader(vertexShader); 参数为着色器对象
-
glShaderSource
- 把这个着色器源码附加到着色器对象
- 参数:1. 待编译的着色器对象 2.指定传递的源码字符串数量 3.顶点着色器真正的源码 4.
- glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
-
glCreateProgram
- 创建一个程序,并返回新创建程序对象的ID引用
- shaderProgram = glCreateProgram();
-
glAttachShader
- 将着色器对象附加到程序
- glAttachShader(shaderProgram, vertexShader);
-
glLinkProgram
- glLinkProgram(shaderProgram);
- 链接
-
glUseProgram
- 调用程序
- glUseProgram(shaderProgram);
- 在glUseProgram函数调用之后,每个着色器调用和渲染调用都会使用这个程序对象(也就是之前写的着色器)了。
- 在把着色器对象链接到程序对象以后,记得删除着色器对象
绘图
-
glDrawArrays
- 使用当前绑定的缓冲对象引进行绘制:
- glDrawArrays(GL_TRIANGLES, 0, 3);
- 参数:1.图元类型 2.指定了顶点数组的起始索引 3.指定我们打算绘制多少个顶点
-
glDrawElements
最后一个参数不是很懂
- 使用当前绑定的索引缓冲对象中的索引进行绘制:
- glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
- 参数:1.图元类型 2.绘制顶点格式 3.索引类型 4. 指定EBO中偏移量
-
线框模式
- 用线框模式绘制你的三角形
- 设置线框模式 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
- 取消线框模式 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
-
图元的类型
- GL_TRIANGLES
GLAD
-
glGetShaderInfoLog
- glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
-
glGetShaderiv
- 检测在调用glCompileShader后编译是否成功
- glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
-
glGetProgramiv
- 检测链接着色器程序是否失败
- glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理