Opengl开发环境
glad
因为OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。取得地址的方法因平台而异,在Windows上会是类似这样:
//glad 加载函数
typedef void (*GL_GENBUFFERS)(GLsizei, GLuint*);
GL_GENBUFFERS glGenBuffers =(GL_GENBUFFERS)glfwGetProcAddress("glGenBuffers"); //window下 调用wglGetProcAddress
GLuint buffer;
glGenBuffers(100, &buffer);
glfw
用glfw创建并管理窗口和 OpenGL 上下文
OpenGL状态机
opengl是一个状态机,opengl的上下文context定义了状态
渲染管线
顶点着色器
将顶点三维坐标,转换为标准化设备坐标。
- 顶点数组对象:Vertex Array Object,VAO
- 顶点缓冲对象:Vertex Buffer Object,VBO
- 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO
VBO是位于GPU上的缓存,可以一次性发送大量顶点数据,需要定义OpenGL如何解释这些内存。创建VBO的步骤:
unsigned int VBO;
glGenBuffers(1, &VBO);
一些重要概念
vertex attribute : 包括positions,colors,纹理坐标等
vertex data:由vertex attributes组成。
vertex buffer objects(VBO):GPU中存储vertex data的空间。
vertex attribute pointer:用于解释vertex data。可以看做“格式”一类的概念。
element buffer objects(EBO):存储vertex data的索引。
vertex attribute objects(VAO):可以看做一个数组,其中元素为EBO,VBO与其对应的vertex attribute pointer。vertex shader从VAO中拿取数据并按其格式渲染。
bind:在VBO和VAO中都存在glBind*这类操作。
OpenGL中的bind有两种用法。
第一种,表示对全局变量的赋值。如“glBindBuffer(GL_ARRAY_BUFFER, &VBO)”就是将“VBO”这个名字赋值给GL_ARRAY_BUFFER这个全局变量。正因如此,在渲染loop中才需要随着场景的变化不断重新bind,即不断给各种全局变量赋新的值。
第二种,表示将数据提交给渲染管线。比如“glBindVertexArray(VAO)”就是将该VAO中的数据提交给vertex shader。
VAO和VBO使用流程
//定义和创建VAO VBO
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// 绑定VAO ,VBO
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//设置VBO数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//配置顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//启用顶点属性
glEnableVertexAttribArray(0);
多个VAO
float firstTriangle[] = {
-0.9f, -0.5f, 0.0f, // left
-0.0f, -0.5f, 0.0f, // right
-0.45f, 0.5f, 0.0f, // top
};
float secondTriangle[] = {
0.0f, -0.5f, 0.0f, // left
0.9f, -0.5f, 0.0f, // right
0.45f, 0.5f, 0.0f // top
};
VAO和VBO配置部分
(1).创建VAO和VBO
(2).对每一个VAO进行单独的配置,流程如下:
绑定VAO(glBindVertexArray)
写入VBO数据(glBufferData)
规定VBO数据解析规则(glVertexAttribPointer)
启动应用(glEnableVertexAttribArray)
//创建VAO
unsigned int VAOs[2];
glGenVertexArrays(2, VAOs);
//创建VBO
unsigned int VBOs[2];
glGenBuffers(2, VBOs);
//绑定VAO
//配置VAO[0];
glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER,VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//glEnableVertexAttribArray表示启用该配置,0表示顶点属性位置值
glEnableVertexAttribArray(0);
//配置VAO[1];
glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//glEnableVertexAttribArray表示启用该配置,0表示顶点属性位置值
glEnableVertexAttribArray(0);
OpenGl基本图元
GL_TRIANGLE
GL_TRIANGLE_STRIP
三角形条带
光照模型
颜色基本理论
看到的物体的颜色,是物体反射的光的颜色
- 白光RGB(1,1,1)
- 黑色光RGB(0,0,0)
- 物体颜色RGB(1.0f, 0.5f, 0.31f)
glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);
Phone Lighting model
源自对物理世界最朴素的认知和模拟:
环境光照:没有绝对的黑,总会有一点光照
void main()
{
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
漫反射光照:正对着光线的地方,光照最强
需要计算光线和平面的法向,所有渲染的时候需要顶点法向
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
镜面光照:沿着光反射的方向看最亮,从观察者的角度
需要计算相机方向(视角方向)和光线反射方向的夹角
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); //这个32是高光的反光度(Shininess)
vec3 specular = specularStrength * spec * lightColor;