《OGL dev》Etay Meiri Tutorial 02 - Hello dot! 笔记
buffer对象(VBOs)提供最短的GPU访问时间。
屏幕映射是将[-1.0,1.0]区间的X、Y和Z坐标,映射到屏幕空间的过程。如果屏幕宽为1024,那么X坐标-1被映射为0,1被映射为1023。
光栅化将顶点数据转化为片元的过程。光栅化依据draw call中指定的拓扑绘制图元。
- 屏幕映射属于哪个阶段没有定论,一些资料归入几何阶段,另一些资料归入光栅化阶段。可以确定的是屏幕映射在光栅化之前或起始时进行。
glut只提供了窗口系统。绘制相关的API都由glew提供。
#include <GL/glew.h>
必须在写其他OpenGL头文件之前。
而glew初始化必须在写在glut初始化之后。
大部分OpenGL对象都使用GLuint类型的handle,如顶点buffer对象。
glGenBuffers(1, &VBO);
,用于创建buffer,1表示创建一个buffer,创建的buffer的handle保存到以&VBO为首地址的数组中,VBO为GLuint数组。
- 这里只创建1个buffer,所以VBO可以是GLuint变量。
- glGen*系列函数用于创建各种类型的对象。
glGenBuffers不会生成相同的handle,除非这个handle已调用glDeleteBuffers删除。
glBindBuffer(GL_ARRAY_BUFFER, VBO);
,为buffer绑定一个target名称。对target名称的操作,在它绑定的buffer上执行。
- GL_ARRAY_BUFFER表示顶点数组。GL_ELEMENT_ARRAY_BUFFER表示索引数组。
- 改变handle(第二个参数),再次调用可以更换绑定的buffer。
- 使用0作为handle调用,则不绑定任何buffer。
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
,将Vertices地址开始sizeof(Vertices)字节,写入到target名称对应的buffer中。
- GL_STATIC_DRAW是一个标记,表示我们之后不会改变buffer内容,相对的是GL_DYNAMIC_DRAW。driver有可能依据标记进行优化,比如某个标记的buffer存储在内存哪个位置更高效,但只是有可能。
glEnableVertexAttribArray(0);
,启动顶点属性,使得顶点buffer可以被管线访问(即可以用来绘制),参数0表示启用坐标属性,2表示启用颜色属性。
glDisableVertexAttribArray(0);
,禁用顶点属性。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
,告诉管线如何解释buffer中的数据。
- 第一个参数0的含义,与
glEnableVertexAttribArray(0);
相同,表示坐标。 - 第二个参数表示一个数据由几部分组成,坐标是x、y、z,所以是3。
- GL_FLOAT表示数据每个部分的类型。
- GL_FALSE表示buffer中的数据在被管线使用之前不归一化。
- 倒数第二个0,表示buffer中数据之间的间隔byte数。
- 最后一个0,表示buffer中数据起始的偏移byte数。
- 因为struct中除了坐标,还会保存颜色,法线之类的数据,所以相同类型的数据可能不会紧密排列,某种类型也不一定从0偏移开始。所以需要最后两个参数。
opengl中draw call分两类:顺序绘制和索引绘制。
- 顺序绘制:GPU遍历顶点buffer中每个顶点,依据draw call中指定的拓扑解释它们。比如draw call指定GL_TRIANGLES,那么顶点0-2是第一个三角形,3-5是第二个,以此类推。相同顶点的三角形在buffer中需要指定多次,造成空间浪费。
- 索引绘制:使用额外的buffer存储顶点buffer中顶点的索引,索引0-2成为第一个三角形,以此类推。索引绘制在游戏中更常见。
glDrawArrays(GL_POINTS, 0, 1);
,顺序绘制draw call。
- GL_POINTS表示拓扑是一个点。
- 第二个参数是顶点buffer中顶点的索引。
- 第三个参数是要绘制的顶点数(从第二个参数指定的索引开始)。