1. Things OpenGL Can Render
图中展示了OpenGL 能够渲染三种类型的物体:点、线和三角形
2. Everything's a Triangle
虽然能够渲染三种类型,但是最终复杂的图形通常由三角形构成,图中的矩形和圣诞树都是由三角形构成的:
接下来我们尝试理解一个简单的三角形是如何完成的
3. Storing Vertex Info
在我们的屏幕中,坐标构成如上图。即屏幕中间为(0,0),范围从-1 到1。所以首先我们为坐标创建一个结构体:
typedef struct {
GLFloat position[3]; // 分别代表x, y, z
}TestVertex;
结构体实例如下:
const static TestVertex vertices[] = {
{{-1.0, -1.0, 0}}, // 左下
{{1.0, -1.0, 0}}, // 右下
{{0, 0, 0}}, // 上
}
4. Sending Vertex Info to GPU
需要经过三个方法:
glGenBuffer() // 在GPU中创建一个VertexBuffer
glBindBuffer() // 绑定并激活VertexBuffer
glBufferData() // 将CPU中数据传输至VertexBuffer,供后续处理
5. Drawing Geometry
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer) // 将VertexBuffer至ArrayBuffer
glDrawArrays(GL_TRIANGLES, 0, 3) // 绘制真正发生的地方
到这里绘制就完成了,但是GPU是如何通过顶点来绘制图像呢,其背后的原理就涉及到了shader
6. Shader
Shader是通过OpenGL ES Shading Language(GLSL)来操作的,这是一个C-like语言。
Shader包括两种类型:
- Vertex Shader:输入顶点,并为顶点输出最终的位置信息
- Fragment Shader:输入像素,输出最终颜色信息
6.1 Vertex Shader
vertex shader的输入是顶点信息,随后通过一系列的transform,输出最终的位置信息,这里为了简单,我们并不做复杂的transform,他的GLSL代码如下:
attribute vec4 a_Positon;
void main(void) {
gl_position = a_Position;
}
6.2 Fragment Shader
fragment shader的输入通常来自于vertex shader,这里为了简化,我们免去了输入,直接输出像素的颜色
void main(void) {
gl_FragColor = vec4(1, 1, 1, 1); // 将一切像素输出为白色
}
7 Demo:Rendering a Triangle
7.1 Add Helper Code
作者提供了一些resource来封装对shader的操作,以及GLSL的实现。需要将这些代码引入工程,可供我们使用+学习。下载地址在此