OpenGL绘制概念

Posted by Haiden on April 22, 2019

一、图形渲染管线

指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程。

图形渲染管线可以被划分为两个主要部分:第一部分把你的3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。下图为 OpenGL 4.3 版本的渲染管线。

二、着色器及处理程序

着色器是图形硬件设备所执行的一类特殊函数,看作专为图形处理单元编译的一种小型程序。

2.1 顶点着色器

顶点着色器(Vertex Shader):把一个单独的顶点作为输入。顶点着色器主要的目的是如何处理顶点、法线等的数据的小程序。

2.2 细分着色器

细分着色器主要描述一个物体的形状。

2.3 几何着色器

几何着色器通过产生新顶点构造出新的图元来生成其他形状。

2.4 图元设置

图元设置将这些顶点与相关的几何图元之间组织起来,准备下一步的剪切和光栅化工作。

2.5 剪切

对进行绘制窗口区域之外的顶点及与其顶点相关的图元会进行一些改动,以保证相关的像素不会在绘制窗口外绘制。这一过程叫做剪切。

2.6 光栅化

光栅化也叫栅格化或者像素化,把矢量图形转化成像素点儿的过程。

2.7 片段着色器

片段着色器的主要目的是计算一个像素的最终颜色,包括如何处理光、阴影、遮挡、环境等等对物体表面的影响,最终生成一副图像的小程序。

三、着色器程序对象

着色器程序对象(Shader Program Object)是多个着色器合并之后并最终链接完成的版本。

如果要使用编译的着色器我们必须把它们链接为一个着色器程序对象,然后在渲染对象的时候激活这个着色器程序。

3.1 创建一个程序对象

1
2
 //创建着色器程序对象
 GLuint program = glCreateProgram();

3.2 链接着色器

把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们。

1
2
3
4
  //附加 vertexShader fragmentShader 着色器
  glAttachShader(program, vertexShader);
  glAttachShader(program, fragmentShader);
  glLinkProgram(program);

3.3 激活程序对象

1
glUseProgram(program);

3.4 删除着色器对象

不再需要着色器时,删除着色器对象。

1
2
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

四、顶点缓冲对象

4.1 VBO定义作用

顶点缓冲对象(Vertex Buffer Objects,VBO)是在显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。

VBO会在GPU内存(通常被称为显存)中储存大量顶点。使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。

每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取操作。

4.2 VBO的创建以及配置

1
2
3
  //创建vertex buffer object对象
	GLuint vboId;  //vertex buffer object句柄
	glGenBuffers(1, &vboId);

创建的VBO可用来保存不同类型的顶点数据,创建之后需要通过分配的ID绑定VBO,对于同一类型的顶点数据一次只能绑定一个VBO。绑定操作通过glBindBuffer来实现,第一个参数指定绑定的数据类型。

1
glBindBuffer(GL_ARRAY_BUFFER, vboId);  

调用glBufferData把用户定义的数据传输到当前绑定的显存缓冲区中。

1
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

第四个参数指定了我们希望显卡如何管理给定的数据。它有三种形式:

  • GL_STATIC_DRAW :数据不会或几乎不会改变。
  • GL_DYNAMIC_DRAW:数据会被改变很多。
  • GL_STREAM_DRAW :数据每次绘制时都会改变。

五、顶点数组对象

顶点数组对象(Vertex Arrary Object,VAO)是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用。

VAO本身并没有存储顶点的相关属性数据,这些信息是存储在VBO中的,VAO相当于是对很多个VBO的引用,把一些VBO组合在一起作为一个对象统一管理。

5.1 VAO的创建和配置

1
2
3
4
//创建vertex array object对象   
	GLuint vaoId;//vertext array object句柄
	glGenVertexArrays(1, &vaoId);
	glBindVertexArray(vaoId);

5.2 解绑VAO

1
glBindVertexArray(0);

六、索引缓冲对象

索引缓冲对象(Element Buffer Object,EBO) 是为了解决同一个顶点多洗重复调用的问题,可以减少内存空间浪费,提高执行效率。当需要使用重复的顶点时,通过顶点的位置索引来调用顶点,而不是对重复的顶点信息重复记录,重复调用。

6.1 EBO的创建

1
2
GLuint EBO;
glGenBuffers(1, &EBO);

6.2 绑定EBO

1
2
3
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//indices为索引数组
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 

6.3 绘制模型

1
2
3
4
5
6
7
 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
 
 --------------------------
第一个参数指定了要绘制的模式;
第二个参数指定要绘制的顶点个数;
第三个参数是索引的数据类型;
第四个参数是可选的EBO中偏移量设定。