计算机图形学实验笔记
计算机视觉学累了就看看计算机图形学…反向消化…
理论看累了就敲敲代码
说不弃坑,就不弃坑|( ´・∧・`)
实验:搭建OpenGL环境
OpenGL版本:3.3
GLFW
GLFW是一个OpenGL的C语言库,是对之前固定管线常用的GLUT的一种改进。
官网下载源代码包(推荐),或者下载32位的预编译的二进制版本。
编译glfw3.lib
我下载的最新3.3版,下载后解压。并新建一个build文件夹。
下载CMake,安装Win32版本。
找到bin文件夹下cmake-gui.exe,
填入源代码路径和build文件夹路径:
Where is the source code: E:/glfw-3.3
Where to build the binaries: E:/glfw-3.3/build
点击Configure按钮,选择合适的生成器(我选择的是VS2015)。点Finish。
再次点击Configure按钮保存设置。
点击Generate按钮,生成工程文件。
在build文件夹打开GLFW.sln文件,并且生成解决方案。
在E:\glfw-3.3\build\src\Debug中所需要的glfw3.lib就有了。
配置
方便起见,我专门建立了一个文件夹OpenGLFiles用来存放相关的头文件和库文件。
在文件夹下新建include文件夹和lib文件夹。
将glfw-3.3\include下的文件复制到新建的include文件夹中,将glfw3.lib复制到新建的lib文件夹中。
新建项目所需工程文件,创建空项目。
打开工程属性页,选择VC++目录-包含目录中加上:
E:\OpenGLFiles\include
库目录加上:
E:\OpenGLFiles\lib
链接器-输入,附加依赖项加上:
glfw3.lib
GLAD
开发者需要在OpenGL运行时获取函数地址并保存在一个函数指针中,取地址方法因平台而异,而GLAD库能简化该过程。
通过GLAD在线服务,language选择C/C++,gl选择3.3,Profile选择Core,Options选中Generate a loader。
点击Generate,下载压缩包。解压后,将include文件夹下的文件复制到我新建的include文件夹里,并且将src下的glad.c添加到工程中。
环境搭好了!
实验:绘制一个窗口
包含头文件
1 |
初始化GLFW
1 | glfwInit(); // 初始化GLFW |
查看GLFW版本
1 | int Major, Minor, Rev; |
创建窗口
1 | GLFWwindow* window = glfwCreateWindow(screen_width, screen_height, "HelloWorld", nullptr, nullptr); |
初始化GLAD
加载OpenGL函数指针地址的函数
1 | if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) |
指定视口
1 | glViewport(0, 0, screen_width, screen_height); |
glViewport函数前两个参数控制窗口左下角的位置,第三、第四个参数
控制渲染窗口的宽度和高度(像素)。
实际上也可以将视口的维度设置为比GLFW的维度小,这样所
有的OpenGL渲染将会在一个更小的窗口中显示,这样我们可以将一
些其它元素显示在OpenGL视口之外。
渲染
1 | while (!glfwWindowShouldClose(window)) |
双缓冲:
单缓冲使图像闪烁(图像是从左到右,从上到下逐像素绘制),不够真实。使用双缓冲规避该问题,前缓冲保存着最终输出的图像,显示在屏幕上。所有渲染指令在后缓冲上绘制,指令执行完毕后交换(swap)前缓冲和后缓冲,图像会立即呈现。
渲染结束,释放资源:
1 | glfwTerminate(); |
运行,此时会看到一个黑色的窗口。
修改窗口颜色
在渲染循环中加入:
1 | glClearColor(0.0f, 0.34f, 0.57f, 1.0f); |
当调用 glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为
glClearColor里所设置的颜色。
运行效果
1 | GLFW 3.3.0 initialized |
完整代码
https://github.com/hubojing/ComputerGraphics/blob/master/CreateWindow.cpp
总结:
- 初始化:GLFW窗口,GLAD。
- 渲染:清空缓冲,交换缓冲区检查触发事件后释放资源。
实验:绘制三角形
初始化
1 | //初始化GLFW |
顶点输入
三角形顶点数据是标准化的设备坐标,即x,y,z轴坐标映射到[-1,1]之间。
1 | const float triangle[]= |
数据处理
VBO
将顶点数据发送到GPU处理。生成一个顶点缓冲对象VBO,将其绑定到顶点缓冲对象上。
作用:不用将顶点数据逐个发送至显卡,可借助VBO一次性发送过去。
再使用glBufferData将顶点数据绑定到当前默认的缓冲上。
1 | //生成并绑定VBO |
VAO
作用:核心模式需要使用VAO,渲染时只需调用一次VAO即可,之前的数据对应存储在VAO中,不用再调用VBO。
1 | GLuint vertex_array_object; |
顶点属性
告诉OpenGL如何解释顶点数据。
1 | //设置顶点属性指针 |
glVertexAttribPointer函数参数含义:
1-顶点着色器位置值
2-顶点属性是一个三分量的向量
3-顶点类型
4-数据是否被标准化(映射到0-1之间)
5-步长(这里表示下组数据在3个float之后)
6-数据偏移量(此处位置属性在数组开头,因此为0)
glEnableVertexAttribArray表示开启0这个通道,默认状态是关闭的。
此时需要解绑VAO和VBO。
原因:
1. 防止继续绑定VAO时影响当前VAO。
2. 使代码更具灵活性,在渲染需要时会再次绑定VAO。
1 | glBindVertexArray(0); |
顶点着色器和片段着色器
顶点着色器
GLSL语言,类似C语言。
源码:
1 | const char *vertex_shader_source = |
第一行:使用OpenGL3.3核心模式
第二行:上面提到的位置值 in表示输入变量
main函数中将顶点数据直接输出到GLSL定义好的内建变量gl_Position中,这是顶点着色器的输出。
(即在顶点着色器这儿上面都没做,只是将顶点位置作为顶点着色器的输出。)
片段着色器
源码:
1 | const char *fragment_shader_source = |
前两行类似上面,out表示输出变量。四分量是RGBA。
生成和编译
目的是为了得到着色器程序,所以首先生成和编译着色器,再链接到着色器程序中。
生成并编译顶点着色器
1 | int vertex_shader = glCreateShader(GL_VERTEX_SHADER); |
生成并编译片段着色器
1 | int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); |
链接顶点和片段着色器至一个着色器程序,并删除着色器
1 | int shader_program = glCreateProgram(); |
渲染
渲染时只需使用链接好的着色器程序就行,不再需要使用顶点和片段着色器。
窗口未关闭就一直进行渲染。
1 | while (!glfwWindowShouldClose(window)) |
这里使用蓝色背景色清空屏幕颜色缓冲。
1 | glClearColor(0.0f, 0.34f, 0.57f, 1.0f); |
接下来使用链接好的着色器和VAO来绘制三角形。
1 | //使用着色器程序 |
其实绘制本身只是一个glDrawArrays函数,参数1表示三角形,参数2表示顶点数组起始索引值,参数3表示要绘制的顶点数量。 绘制结束后解除绑定。
双缓冲技术:
1 | //交换缓冲 |
善后工作
1 | //删除VAO和VBO |
实验效果
完整代码
https://github.com/hubojing/ComputerGraphics/blob/master/Triangle
总结:
- 初始化。
- 数据处理:给定顶点数据,生成并绑定VAO和VBO,准备在GPU处理,设置顶点属性指针(告诉OpenGL怎么处理数据)。
- 着色器:生成并编译顶点和片段着色器,链接为着色器程序。
- 渲染绘制三角形。
下一个实验准备中…