( 本文对应学习章节:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ )
0.前言本章节主要介绍了VAO/VBO以及顶点着色器/片段着色器,并绘制了一个三角形。
1.重要的东西在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline)管理的。图形渲染管线接受一组3D坐标,然后把它们转变为你屏幕上的有色2D像素输出。图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。
由于我这里只是应用型的学习,就不深入讲解(好吧,毕竟我也还没学会),具体的渲染流程请参考前言中的链接。对于应用,主要关注顶点着色器(Vertex Shader)和片段着色器(Fragment Shader)就行了。而且,在现代OpenGL中,我们必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器)。顶点着色器可用于传统的基于顶点操作,例如通过矩阵变换位置、计算照明方程式以生成逐顶点的颜色以及生成或者变换纹理坐标。片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。着色器需要用着色器语言GLSL(OpenGL Shading Language)编写,语法类似C语言,这个是后面章节的内容。
另外一个重点是VAO(顶点数组对象:Vertex Array Object)和VBO(顶点缓冲对象:Vertex Buffer Object)。VAO是一个对象,其中包含一个或者更多的Vertex Buffer Objects。而VBO是Graphics Card中的一个内存缓冲区,用来保存顶点信息,颜色信息,法线信息,纹理坐标信息和索引信息等等。一个VAO有多个VBO,它们之间通过上下文关联,只有唯一的激活VAO,在VAO后配置的VBO都属于该VAO(要在配置顶点属性glVertexAttribPointer之前,而glEnableVertexAttribArray在glVertexAttribPointer前后调用都可以)。不过有点没懂的是一开始我把VBO配置完了才去创建VAO,也是正常的。
还有就是顶点中的坐标,使用的标准化设备坐标(Normalized Device Coordinates, NDC)。与通常的屏幕坐标不同,y轴正方向为向上,(0, 0)坐标是这个图像的中心,而不是左上角。
还有就是顶点着色器中的 layout(location = 0) 这个输入偏移怎么来的,学到后半部分才看到是使用glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据。每个顶点属性从一个VBO管理的内存中获得它的数据,而具体是从哪个VBO(程序中可以有多个VBO)获取则是通过在调用glVertexAttribPointer时绑定到GL_ARRAY_BUFFER的VBO决定的。
(对于VAO/VBO或者着色器的操作流程还有疑问可以参考教程的参考http://antongerdelan.net/opengl/hellotriangle.html)
2.第一个三角形代码中着色器应用流程:
- glCreateShader 创建着色器对象
- glShaderSource 把着色器代码附加到着色器对象上
- glCompileShader 编译着色器
- glGetShaderiv 检测是否编译成功
- glCreateProgram 创建程序对象
- glAttachShader 把顶点和片段着色器附加到程序对象
- glLinkProgram 链接程序对象
- glGetProgramiv 检测是否链接成功
- glDeleteShader 删除着色器对象(附加到了程序对象,后面不需要了)
- glUseProgram 每次渲染时使用,使程序对象作为当前渲染状态的一部分
代码中VAO/VBO应用流程:
- glGenVertexArrays 创建VAO
- glGenBuffers 创建VBO
- glBindVertexArray 绑定VAO
- glBindBuffer 绑定VBO
- glBufferData 把定义的顶点数据复制到缓冲的内存中
- glVertexAttribPointer 定义通用顶点属性数据的数组
- glEnableVertexAttribArray 使能顶点属性数组
- glBindVertexArray 每次渲染时使用,绑定一个顶点数组对象
- glDrawArrays 每次渲染时使用,绘制图元
- glDeleteVertexArrays 退出时删除VAO
- glDeleteBuffers 退出时删除VBO
从这些接口有点理解了OpenGL是以状态机来实现的。
#include
#include
#include
void error_callback(int error, const char* description); //声明
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void bufferresize_callback(GLFWwindow* window, int width, int height);
//顶点着色器程序,着色器语言GLSL下一节才学
//为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量
//layout对应glVertexAttribPointer中的参数1
static const char* vertex_code = R"(
#version 330 core
layout(location=0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos,1.0f);
}
)";
//片段着色器代码
//片段着色器所做的是计算像素最后的颜色输出
static const char* frag_code = R"(
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(0.1f,1.0f,0.1f,1.0f);
}
)";
int main()
{
if (!glfwInit()) {
return -1; //初始化GLFW库失败
}
//注册错误回调,大多数事件都是通过回调报告的
glfwSetErrorCallback(error_callback);
//设置最低主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//设置最低次版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//设置为核心模式
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //mac系统加这一句
//创建窗口对象,如果要销毁窗口则glfwDestroyWindow(window)
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
//创建失败则返回NULL,退出程序
if (window == NULL)
{
std::cout
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?