@@ -43,6 +43,10 @@ OpenGL ES由OpenGL裁剪而来,因此有必要了解一下两者版本的对
4343
4444
4545
46+ 图像数据无非是一个个的像素点,对图像数据的处理无非是对每个像素点进行计算后重新赋值,一般来说对每个像素点的计算都比较独立,计算也相对简单。CPU虽然计算能力强大,但是并行处理能力有限,对一张720P的图片,一共包含720* 1280=921600个像素,要进行这么多次运算,CPU也要望洋兴叹了。GPU与CPU相比最大的优势就是并行处理能力,一般移动端的GPU也要包含数千个处理单元,这些处理单元虽然计算能力比不上CPU,但是却可以同时处理几千个像素点。像素点数据的计算相对简单,而且可以同时处理几千个像素点,图像数据用GPU来做计算就非常适合了。而怎么使用GPU呢?这就要介绍到目前使用最广泛的2D、3D矢量图形沉浸API:OpenGL了。
47+
48+
49+
4650### Android中的OpenGL ES
4751
4852Android中OpenGL ES的版本支持如下:
@@ -69,8 +73,8 @@ OpenGL ES的实现有2中方式:
6973
7074- OpenGL自身是一个巨大的状态机: 描述该如何操作的所有变量的大集合
7175- OpenGL的状态通常被称为上下文(Context)
72- - 状态设置函数(State-changing Function)
73- - 状态应用的函数(State-using Function)
76+ - 状态设置函数(State-changing Function): 该类函数将会改变上下文
77+ - 状态应用的函数(State-using Function): 该类函数会根据当前OpenGL的状态执行一些操作。
7478
7579![ image] ( https://github.com/CharonChui/Pictures/blob/master/opengl_state_machine.png?raw=true )
7680
@@ -109,7 +113,21 @@ struct object_Window_Target {
109113}
110114```
111115
112- 通常把OpenGL上下文比作一个大的结构体,包含很多子集。
116+
117+ 但是,这样也有问题:
118+
119+ - 当前状态只有一份,如果每次显示不同的效果,都重新配置会很麻烦。
120+ - 这时候我们就需要一些小助理(对象),来帮忙记录某些状态信息,以便复用。
121+
122+ 如果我们有10种子集,那就需要10个小助理(对象),而当前状态(Context,只有一份)可以通过装配这些对象来完成。
123+
124+ ![ image] ( https://github.com/CharonChui/Pictures/blob/master/opengl_zhuli.jpg?raw=true )
125+
126+
127+ 通常把OpenGL上下文比作一个大的结构体,包含很多子集。
128+
129+ 在OpenGL中一个对象是指一些选项的集合,它代表OpenGL状态的一个子集。
130+ 比如,我们可以用一个对象来代表绘制窗口的设置,之后我们就可以设置它的大小等。
113131
114132``` C
115133// OpenGL的状态
@@ -120,20 +138,48 @@ struct OpenGL_Context {
120138}
121139```
122140
123- 但是,这样也有问题:
124141
125- - 当前状态只有一份,如果每次显示不同的效果,都重新配置会很麻烦。
126- - 这时候我们就需要一些小助理(对象),来帮忙记录某些状态信息,以便复用。
127142
128- 如果我们有10种子集,那就需要10个小助理(对象),而当前状态(Context,只有一份)可以通过装配这些对象来完成。
143+ ``` c++
144+ // 创建对象
145+ unsigned int objectId = 0 ;
146+ glGenObject (1, &objectId);
129147
130- ![ image] ( https://github.com/CharonChui/Pictures/blob/master/opengl_zhuli.jpg?raw=true )
148+ // 绑定对象至上下文
149+ glBindObject(GL_WINDOW_TARGET, objectId);
150+ // 设置当前绑定到GL_WINDOW_TARGET的对象的一些选项
151+ glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
152+ glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
153+ // 将上下文对象设回默认
154+ glBindObject(GL_WINDOW_TARGET, 0);
155+ ```
156+ 上面这一小段代码展示了以后使用OpenGL时常见的工作流。
157+
158+ - 我们首先创建一个对象,然后用一个id保存它的引用(实际数据被存储在后台)。
159+ - 然后我们将对象绑定至上下文的目标位置(例子中窗口对象目标的位置被定义成GL_WINDOW_TARGET)
160+ - 接下来我们设置窗口的选项。
161+ - 最后我们将目标位置的对象id设回0,解绑这个对象。
131162
163+ **设置的选项将被保存在objectId所引用的对象中,一旦我们重新绑定这个对象到GL_WINDOW_TARGET位置,这些选项就会重新生效。**
164+
165+ 使用对象的一个好处是在程序中,我们不止可以定义一个对象,并设置它们的选项,每个对象都可以是不同的设置。
166+
167+ 在我们执行一个使用OpenGL状态的操作的时候,只需要绑定含有需要的设置的对象即可。
132168
133169
134170
135171### 渲染管线
136172
173+
174+ 渲染管线有时也称为渲染流水线,一般由显示芯片(GPU)内部处理图形信号的并行处理单元组成。
175+ 这些并行处理单元两两之间是相互独立的,在不同型号的硬件上独立处理单元的数量也有很大的差异。一般越高端型号的硬件,其中独立处理单元的数量也就越多。
176+
177+
178+ 与普通应用程序通过CPU串行执行不同的是,渲染工作是通过渲染管线由多个相互独立的处理单元进行并行处理的,这种模式极大的提升了渲染效率。
179+
180+ 从另一个角度看,OpenGLES中的渲染管线实际上指的是一系列绘制过程。
181+ 这些过程输入的是待渲染3D物体的相关描述信息数据,经过渲染管线,输出的是一帧想要的图像。
182+
137183在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。
138184
1391853D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程)管理的。
@@ -448,6 +494,16 @@ OpenGL中最基础且唯一的多边形就是三角形,所有更复杂的图
448494
449495### 片段着色器或片元着色器(Fragment Shader)
450496
497+
498+ 显示设备屏幕都是离散化的(由一个一个的像素组成),因此还需要将投影的结果离散化。
499+ 将其分解为一个个离散化的小单元,这些小单元一版称为片元。
500+
501+ 其实每个片元都对应于帧缓冲中的一个像素,之所以不直接称为像素是因为3D空间中的物体是可以相互遮挡的。而一个3D场景最终显示到屏幕上虽然是一个整体,但每个3D物体的每个图元是独立处理的。这就可能出现这样的情况,系统先处理的是位于离观察点较远的图元,其光栅化成为了一组图元,暂时送入帧缓冲的对应位置。
502+
503+ 但后面继续处理离观察点较近的图元时也光栅化出了一组片元,两组片元中有对应到帧缓冲中同一个位置的,这时距离近的片元将覆盖距离远的片元(如何覆盖的检测是在深度检测阶段完成的)。
504+
505+ 因此,某片元就不一定能成为最终屏幕上的像素,称为像素就不准确了,可以将其理解为候选像素。
506+
451507使用颜色或纹理(texture)渲染图形表面的OpenGLES代码。
452508
453509
@@ -606,7 +662,7 @@ EGL为双缓冲工作模式(Double Buffer),既有一个Back Frame Buffer和一
606662
6076636 . 设置OpenGL的渲染环境
608664
609- eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);该方法的参数意义很明确,该方法在异步线程中被调用,该线程也会被成为GL线程 ,一旦设定后,所有OpenGL渲染相关的操作都必须放在该线程中执行。
665+ eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);该方法的参数意义很明确,该方法在异步线程中被调用,该线程也会被称为GL线程 ,一旦设定后,所有OpenGL渲染相关的操作都必须放在该线程中执行。
610666
611667通过上述操作,就完成了EGL的初始化设置,便可以进行OpenGL的渲染操作。所有EGL命令都是以egl前缀开始,对组成命令名的每个单词使用首字母大写(如eglCreateWindowSurface)。
612668
0 commit comments