1:首先了解GPU和渲染管道工作原理。
2:解释VAO、VBO、EBO
- 顶点数组对象:Vertex Array Object,VAO
- 顶点缓冲对象:Vertex Buffer Object,VBO
- 元素缓冲对象:Element Buffer Object
在定义VBO时我们一般绑定一组顶点数据或者顶点信息。举例:
float vertices[] = {
// positions // normals // texture coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
......
}
//绑定数据到VBO
//定义VBO
unsigned int VBO;
//生成缓冲区-----数量-名称
glGenBuffers(1, &VBO);
//牵扯到上下文切换,绑定此处的VBO为当前环境中的VBO,同一时间只能存在一种状态
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//将数据绑定到VBO中,推送至缓冲区
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
接下来就是VAO,VAO使用的是VBO中的数据,但是VAO可以有很多种读取方式,举例:
unsigned int lightCubeVAO, cubeVAO;
//---------------物体--------
//绑定VBO(切换上下文)
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//绑定VAO
glGenVertexArrays(1, &cubeVAO);
glBindVertexArray(cubeVAO);
// 位置数据信息
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 法线信息
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//光照贴图信息
glVertexAttribPointer(2, 2, GL_FLOAT,GL_FALSE, 8*sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
//-----------------灯光-------
//只使用位置信息
//绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//绑定VAO
glGenVertexArrays(1, &lightCubeVAO);
glBindVertexArray(lightCubeVAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
最后就是EBO,EBO就是让多个重复的点重合在一起,节省资源,例如:
//三角形顶点信息
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
//每个三角形顶点数据信息
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//画图时根据索引绘制
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
3:理解 vertex、fragment
好我们已经将顶点数据准备好了,接下来我们需要写shader了,一般有2个文件要写,第一个是顶点着色器(vertex),一个是片段着色器(fragment)。
首先是Vertex文件,举例说明:
//版本信息
#version 330 core
//接受VAO输入的值
layout (location = 0) in vec3 aPos;
//脚本和shader交互传值用uniform
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
//将顶点值输出--------渲染管道进行顶点变化
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
然后是fragment,举例说明:
#version 330 core
//out接收数据 in输出数据
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0); // set alle 4 vector values to 1.0
}
4:总结
其实我们的效果主要在shader中实现,在脚本代码中主要准备的数据信息,和一些其他信息,比如纹理贴图、光照贴图、法线贴图等。在shader中实现渲染管道的实现,渲染设置,其中脚本和shader也可以用uniform交互。其实很容易实现。