Skip to content

Commit 7032443

Browse files
committed
# Conflicts: # VideoDevelopment/OpenGL/1.OpenGL简介.md # VideoDevelopment/OpenGL/10.GLSurfaceView+MediaPlayer播放视频.md # VideoDevelopment/OpenGL/5.OpenGL ES绘制三角形.md # VideoDevelopment/OpenGL/6.OpenGL ES绘制矩形及圆形.md # VideoDevelopment/OpenGL/7.OpenGL ES着色器语言GLSL.md # VideoDevelopment/OpenGL/8.GLES类及Matrix类.md # VideoDevelopment/OpenGL/9.OpenGL ES纹理.md
2 parents 429d21f + 6521d4f commit 7032443

8 files changed

+319
-60
lines changed

VideoDevelopment/OpenGL/1.OpenGL简介.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## 1.OpenGL简介
22

3+
最近想要在播放器上做一个效果,需要用到OpenGL,一直以来也没关注学习过,就想着学习学习。在网上已经有很多文章,这里为什么还要写?主要是因为在学的时候发现那些文章看完后还是雨里雾里的不明白。要不就是不连贯,要不就是各种错误,各种理解的不对,导致我稀里糊涂的,干脆我不看了,买了一本书,看了书之后再去看文章就彻底明白了,所以我想写一个简单的,能从入门开始一步步学习的,能简单的学会,文章里面有一些是从下面写的参考链接中拷贝过来的,也有一些是自己从书上看的。
4+
35
[OpenGL官网](https://www.opengl.org/)
46

57
OpenGL(Open Graphics Library开放图形库)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口。
@@ -51,7 +53,9 @@ OpenGL ES 3.0兼容了2.0,并丰富了更多功能。
5153

5254
OpenGL渲染管线的流程为: 顶点数据 -> 顶点着色器 -> 图元装配 -> 几何着色器 -> 光栅化 -> 片段着色器 -> 逐片段处理 -> 帧缓冲
5355

54-
如下图,阴影的表示OpenGL ES 3.0管线中可编程阶段。
56+
OpenGL ES 3.0实现了具有可编程着色功能的图形管线,有两个规范组成:OpenGL ES3.0 API规范和OpenGL ES着色语言3.0规范(OpenGL ES SL)。
57+
58+
如下图,展示了OpenGL ES 3.0的图形管线。阴影的表示OpenGL ES 3.0管线中可编程阶段。
5559

5660
![](https://raw.githubusercontent.com/CharonChui/Pictures/master/oepngl_es_pip.jpg)
5761

@@ -168,6 +172,8 @@ OpenGL是一个仅仅关注图像渲染的图像接口库,在渲染过程中
168172

169173
### EGL
170174

175+
OpenGL ES API没有提及如何创建渲染上下文,或者渲染上下文如何连接到原生窗口系统。EGL是Khronos渲染API(如OpenGL ES)和原生窗口系统之间的接口。
176+
171177
在OpenGL的设计中,OpenGL是不负责管理窗口的,窗口的管理交由各个设备自己完成。具体的来说就是iOS平台上使用EAGL提供本地平台对OpenGL的实现,在Android平台上使用EGL提供本地平台对OpenGL的实现。OpenGL其实是通过GPU进行渲染。但是我们的程序是运行在CPU上,要与GPU关联,这就需要通过EGL,它相当于Android上层应用于GPU通讯的中间层。
172178

173179
EGL为双缓冲工作模式,既有一个Back Frame Buffer和一个Front Frame Buffer,正常绘制的目标都是Back Frame Buffer,绘制完成后再调用eglSwapBuffer API,将绘制完毕的FrameBuffer交换到Front Frame Buffer并显示出来。
@@ -198,9 +204,7 @@ EGL为双缓冲工作模式,既有一个Back Frame Buffer和一个Front Frame
198204

199205
eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);该方法的参数意义很明确,该方法在异步线程中被调用,该线程也会被成为GL线程,一旦设定后,所有OpenGL渲染相关的操作都必须放在该线程中执行。
200206

201-
通过上述操作,就完成了EGL的初始化设置,便可以进行OpenGL的渲染操作。
202-
203-
207+
通过上述操作,就完成了EGL的初始化设置,便可以进行OpenGL的渲染操作。所有EGL命令都是以egl前缀开始,对组成命令名的每个单词使用首字母大写(如eglCreateWindowSurface)。
204208

205209
#### OpenGL纹理
206210

VideoDevelopment/OpenGL/10.GLSurfaceView+MediaPlayer播放视频.md

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,60 @@
11
## 10.GLSurfaceView+MediaPlayer播放视频
22

3+
### 相机预览
4+
5+
1. 在GLSurfaceView.Render中创建一个纹理,再使用该纹理创建一个SurfaceTexture。
6+
2. 使用该SurfaceTexture创建一个Surface传给相机,相机预览数据就会输出到这个纹理上了。
7+
3. 使用GLSurfaceView.Render将该纹理渲染到GLSurfaceView的窗口上。
8+
4. 使用SurfaceTexture的setOnFrameAvailableListener方法给SurfaceTexture添加一个数据帧可用的监听器,在监听器中调用GLSurfaceView的requestRender方法渲染该帧数据,这样相机每次输出一帧数据就可以渲染一次,在GLSurfaceView窗口中就可以看到相机的预览数据了。
9+
10+
- 顶点着色器
11+
12+
```xml
13+
#version 300 es
14+
15+
layout (location = 0) in vec4 a_Position;
16+
layout (location = 1) in vec2 a_texCoord;
17+
18+
out vec2 v_texCoord;
19+
20+
void main()
21+
{
22+
gl_Position = a_Position;
23+
v_texCoord = a_texCoord;
24+
}
25+
```
26+
27+
- 片段着色器
28+
29+
这里需要注意一下,就是做相机预览的话,纹理的类型需要使用samplerExternalOES,而不是之前渲染图片的sampler2D。
30+
31+
```xml
32+
#version 300 es
33+
#extension GL_OES_EGL_image_external_essl3 : require
34+
precision mediump float;
35+
36+
in vec2 v_texCoord;
37+
out vec4 outColor;
38+
uniform samplerExternalOES s_texture;
39+
40+
void main(){
41+
outColor = texture(s_texture, v_texCoord);
42+
}
43+
```
44+
45+
46+
47+
48+
49+
50+
51+
52+
53+
### 视频播放
54+
355
平时的视频播放都是使用mediaplayer+textureview或者mediaplayer+surfaceview,但是如果我们要对视频进行一些OpenGL的操作,打个比方说我要在视频播放的时候添加一个滤镜,这个时候就需要用都SurfaceTexture了。
456

5-
大体步骤如下:
57+
大体步骤如下:
658

759
GLSurfaceView -> setRender -> onSurfaceCreated回调方法中构造一个SurfaceTexture对象,然后设置到Camera预览或者MediaPlayer中 -> SurfaceTexture中的回调方法onFrameAvailable来得知一帧的数据真好完成 -> requestRender通知Render来绘制数据 -> 在Render的回调方法onDrawFrame中调用SurfaceTexture的updateTexImage方法来获取一帧数据,然后开始使用GL进行绘制预览。
860

@@ -116,7 +168,7 @@ public class VideoActivity extends Activity {
116168

117169

118170

119-
[上一篇: 9.OpenGL ES纹理](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/9.OpenGL%20ES%E7%BA%B9%E7%90%86.md)
171+
[上一篇: 9.OpenGL ES纹理](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/9.OpenGL%20ES%E7%BA%B9%E7%90%86.md)
120172
[下一篇: 11.OpenGL ES滤镜](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/11.OpenGL%20ES%E6%BB%A4%E9%95%9C.md)
121173

122174
---

VideoDevelopment/OpenGL/11.OpenGL ES滤镜.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,46 @@
11
## 11.OpenGL ES滤镜
22

3-
滤镜其实就是利用纹理。
3+
给图像添加滤镜本质就是图片处理,也就是对图片的像素进行计算,简单来说,图像处理的方法可以分为三类:
4+
5+
- 点算:当前像素的处理只和自身的像素值有关,和其他像素无关,比如灰度处理。
6+
- 领域算:当前像素的处理需要和相邻的一定范围内的像素有关,比如高斯模糊。
7+
- 全局算:在全局上对所有像素进行统一变换,比如几何变换。
8+
9+
### 灰色滤镜
10+
11+
和前一篇文章基本一样,只是修改一下片段着色器的代码,原理就是在片段着色器中去处理颜色,让RGB三个通道的颜色取均值:
12+
13+
```
14+
#version 300 es
15+
#extension GL_OES_EGL_image_external_essl3 : require
16+
precision mediump float;
17+
18+
in vec2 v_texCoord;
19+
out vec4 outColor;
20+
uniform samplerExternalOES s_texture;
21+
22+
//灰度滤镜,具体去处理颜色
23+
void grey(inout vec4 color){
24+
float weightMean = color.r * 0.3 + color.g * 0.59 + color.b * 0.11;
25+
color.r = color.g = color.b = weightMean;
26+
}
27+
28+
void main(){
29+
//拿到颜色值
30+
vec4 tmpColor = texture(s_texture, v_texCoord);
31+
//对颜色值进行处理
32+
grey(tmpColor);
33+
//将处理后的颜色值输出到颜色缓冲区
34+
outColor = tmpColor;
35+
}
36+
37+
```
38+
39+
40+
41+
42+
43+
444

545
滤镜的编写主要是靠基类。
646

@@ -24,6 +64,36 @@ RGB三个通道的颜色取反,而alpha通道不变。
2464

2565
纹理默认传入的读取范围是(0,0)到(1,1)内的颜色值。如果对读取的位置进行调整修改,那么就可以做出各种各样的效果,例如缩放动画就是让读取的范围改成(-1,-1)到(2,2)。
2666

67+
## 看完了疯了是不是,要做个滤镜效果,各种计算我实在弄不明白
68+
69+
最简单的方法就是通过LUT方法,通过设计师提供的LUT文件来实现预定的滤镜效果。基本思路如下:
70+
71+
- 准备LUT文件
72+
- 加载LUT文件到OpenGL纹理
73+
- 将纹理传递给片段着色器
74+
- 根据LUT,在片段着色器中对图像的颜色值进行映射,得到滤镜后的颜色进行输出
75+
76+
77+
78+
### 离屏渲染
79+
80+
之前已经将相机的预览数据输出到OpenGL的纹理上,渲染的时候OpenGL直接将纹理渲染到屏幕上。但是如果想要对纹理进行进一步的处理,就不能直接渲染到屏幕上,而是需要先渲染到屏幕外的缓冲区(FrameBuffer)处理完后再渲染到屏幕。渲染到缓冲区的操作就是离屏渲染。主要步骤如下:
81+
82+
- 准备离屏渲染所需要的FrameBuffer和纹理对象。
83+
- 切换渲染目标(屏幕->缓冲区)
84+
- 执行渲染
85+
- 重置渲染目标(缓冲区 -> 屏幕)
86+
87+
88+
89+
90+
91+
92+
93+
94+
95+
96+
2797

2898

2999

VideoDevelopment/OpenGL/5.OpenGL ES绘制三角形.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ OpenGL ES的绘制需要有以下步骤:
2424

2525
下一步,使用in关键字,在顶点着色器中声明所有的输入顶点属性(Input Vertex Attribute)。现在我们只关心位置(Position)数据,所以我们只需要一个顶点属性。GLSL有一个向量数据类型,它包含1到4个float分量,包含的数量可以从它的后缀数字看出来。由于每个顶点都有一个3D坐标,我们就创建一个vec3输入变量position。我们同样也通过layout (location = 0)设定了输入变量的位置值(Location)你后面会看到为什么我们会需要这个位置值。
2626

27-
为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量,它在幕后是vec4类型的。在main函数的最后,我们将gl_Position设置的值会成为该顶点着色器的输出。由于我们的输入是一个3分量的向量,我们必须把它转换为4分量的。我们可以把vec3的数据作为vec4构造器的参数,同时把w分量设置为1.0f(我们会在后面解释为什么)来完成这一任务。
27+
为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量,它在幕后是vec4类型的。在main函数中只是将position的值转换后赋值给gl_Position。由于我们的输入是一个3分量的向量,我们必须把它转换为4分量的。我们可以把vec3的数据作为vec4构造器的参数,同时把w分量设置为1.0f(我们会在后面解释为什么)来完成这一任务。
28+
29+
这个position的值是哪里进行赋值的呢? 是通过后面java代码中的draw函数来进行赋值的。每个顶点着色器都必须在gl_Position变量中输出一个位置。这个变量定义传递给管线下一个阶段的位置。
2830

2931
- 编译着色器
3032

@@ -42,7 +44,7 @@ OpenGL ES的绘制需要有以下步骤:
4244
}
4345
```
4446

45-
片段着色器只需要一个输出变量,这个变量是一个4分量向量,它表示的是最终的输出颜色,我们应该自己将其计算出来。我们可以用out关键字声明输出变量,这里我们命名为color。下面,我们将一个alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。之后也是需要编译着色器。
47+
片段着色器只需要一个输出变量,这个变量是一个4分量向量,它表示的是最终的输出颜色,我们应该自己将其计算出来。我们可以用out关键字声明输出变量,这里我们命名为color。下面,我们将一个alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。之后也是需要编译着色器。片段着色器声明的这个输出变量color的值会被输出到颜色缓冲区。,然后颜色缓冲区再通过EGL窗口显示。
4648

4749
- 着色器程序(Shader Program Object)
4850

@@ -56,7 +58,7 @@ OpenGL ES的绘制需要有以下步骤:
5658
glLinkProgram(shaderProgram);
5759
```
5860

59-
链接完后需要使用glUseProgram方法,用刚创建的程序对象作为参数,以激活这个程序对象。
61+
链接完后需要使用glUseProgram方法,用刚创建的程序对象作为参数,以激活这个程序对象。调用glUserProgram方法后,所有后续的渲染将用连接到这个程序对象的顶点和片段着色器进行。
6062

6163
- 链接顶点属性
6264

@@ -86,12 +88,13 @@ OpenGL ES的绘制需要有以下步骤:
8688

8789
下面需要实现GLSurfaceView.Render接口,实现要绘制的部分:
8890

91+
- 用EGL创建屏幕上的渲染表面(GLSurfaceView内部实现)
8992
- 写顶点着色器和片段着色器文件。
9093
- 加载编译顶点着色器和片段着色器。
9194
- 确定需要绘制图形的坐标和颜色数据。
9295
- 创建program对象,连接顶点和片断着色器,将坐标数据、颜色数据传到OpenGL ES程序中。]
9396
- 设置视图窗口(viewport)。
94-
- 使颜色缓冲区的内容显示到屏幕上
97+
- 使颜色缓冲区的内容显示到EGL窗口上
9598

9699

97100

@@ -112,9 +115,9 @@ Preferences -> Plugins -> 搜GLSL Support安装就可以了。
112115
```glsl
113116
// 声明着色器的版本
114117
#version 300 es
115-
// 顶点着色器的顶点位置,输入一个名为vPosition的4分量向量,layout (location = 0)表示这个变量的位置是顶点属性0
118+
// 顶点着色器的顶点位置,输入一个名为vPosition的4分量向量,layout (location = 0)表示这个变量的位置是顶点属性中的第0个属性
116119
layout (location = 0) in vec4 vPosition;
117-
// 顶点着色器的顶点颜色数据,输入一个名为aColor的4分量向量,layout (location = 1)表示这个变量的位置是顶点属性1
120+
// 顶点着色器的顶点颜色数据,输入一个名为aColor的4分量向量,layout (location = 1)表示这个变量的位置是顶点属性中的第1个属性
118121
layout (location = 1) in vec4 aColor;
119122
// 输出一个名为vColor的4分量向量,后面输入到片段着色器中。
120123
out vec4 vColor;
@@ -128,6 +131,8 @@ Preferences -> Plugins -> 搜GLSL Support安装就可以了。
128131
}
129132
```
130133

134+
大体意思:使用OpenGL ES3.0版本,将图形顶点数据采用4分向量的数据结构绑定到着色器的第0个属性上,属性的名字是vPosition,然后再有一个颜色的4分向量绑定到做色漆的第1个属性上,属性的名字是aColor,另外还会输出一个vColor,着色器执行的时候,会将vPosition的值传递给用来表示顶点最终位置的内建变量gl_Position,将顶点最终大小的gl_PointSize设置为10,并将aColor的值复制给要输出额vColor。
135+
131136
- 片段着色器(fragment_simple_shade.glsl)
132137

133138
```glsl
@@ -210,12 +215,12 @@ class MyGLRenderer implements GLSurfaceView.Renderer {
210215
/*****************1.声明绘制图形的坐标和颜色数据 end**************/
211216
public MyGLRenderer() {
212217
/****************2.为顶点位置及颜色申请本地内存 start************/
213-
//顶点位置相关
218+
//将顶点数据拷贝映射到native内存中,以便OpenGL能够访问
214219
//分配本地内存空间,每个浮点型占4字节空间;将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
215-
vertexBuffer = ByteBuffer.allocateDirect(triangleCoords.length * BYTES_PER_FLOAT)
216-
.order(ByteOrder.nativeOrder())
217-
.asFloatBuffer();
218-
vertexBuffer.put(triangleCoords);
220+
vertexBuffer = ByteBuffer.allocateDirect(triangleCoords.length * BYTES_PER_FLOAT) // 直接分配native内存
221+
.order(ByteOrder.nativeOrder()) // 和本地平台保持一致的字节序
222+
.asFloatBuffer(); // 将底层字节映射到FloatBuffer实例,方便使用
223+
vertexBuffer.put(triangleCoords); // 将顶点数据拷贝到native内存中
219224
// 将数组数据put进buffer之后,指针并不是在首位,所以一定要position到0,至关重要!否则会有很多奇妙的错误!将缓冲区的指针移动到头部,保证数据是从最开始处读取
220225
vertexBuffer.position(0);
221226

@@ -254,17 +259,18 @@ class MyGLRenderer implements GLSurfaceView.Renderer {
254259
}
255260
public void onDrawFrame(GL10 unused) {
256261
/**********6.绘制************/
257-
//把颜色缓冲区设置为我们预设的颜色
262+
//把颜色缓冲区设置为我们预设的颜色,绘图设计到多种缓冲区类型:颜色、深度和模板。这里只是向颜色缓冲区中绘制图形
258263
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
259264

260-
//绑定vertex坐标数据,告诉OpenGL可以在缓冲区vertextBuffer中获取数据
265+
//0是上面着色器中写的vPosition的变量位置(location = 0)。意思就是绑定vertex坐标数据,然后将在vertextBuffer中的顶点数据传给vPosition变量。
266+
// 你肯定会想,如果我在着色器中不写呢?int vposition = glGetAttribLocation(program, "vPosition");就可以获得他的属性位置了
261267
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
262-
//启用顶点位置句柄
268+
//启用顶点变量,这个0也是vPosition在着色器变量中的位置,和上面一样,在着色器文件中的location=0声明的
263269
GLES30.glEnableVertexAttribArray(0);
264270

265271
//准备颜色数据
266272
/**
267-
* glVertexAttribPointer()方法的参数分别为:
273+
* glVertexAttribPointer()方法的参数上面的也说过了,这里再按照这个场景说一下分别为:
268274
* index:顶点属性的索引.(这里我们的顶点位置和颜色向量在着色器中分别为0和1)layout (location = 0) in vec4 vPosition; layout (location = 1) in vec4 aColor;
269275
* size: 指定每个通用顶点属性的元素个数。必须是1、2、3、4。此外,glvertexattribpointer接受符号常量gl_bgra。初始值为4(也就是涉及颜色的时候必为4)。
270276
* type:属性的元素类型。(上面都是Float所以使用GLES30.GL_FLOAT);
@@ -862,8 +868,7 @@ class TriangleRender implements GLSurfaceView.Renderer {
862868

863869

864870

865-
866-
[上一篇: 4.GLTextureView实现](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/4.GLTextureView%E5%AE%9E%E7%8E%B0.md)
871+
[上一篇: 4.GLTextureView实现](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/4.GLTextureView%E5%AE%9E%E7%8E%B0.md)
867872
[下一篇: 6.OpenGL ES绘制矩形及圆形](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/6.OpenGL%20ES%E7%BB%98%E5%88%B6%E7%9F%A9%E5%BD%A2%E5%8F%8A%E5%9C%86%E5%BD%A2.md)
868873

869874
---

VideoDevelopment/OpenGL/6.OpenGL ES绘制矩形及圆形.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ public class CircularRender implements GLSurfaceView.Renderer {
501501
```
502502

503503

504-
[上一篇: 5.OpenGL ES绘制三角形](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/5.OpenGL%20ES%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2.md)
504+
[上一篇: 5.OpenGL ES绘制三角形](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/5.OpenGL%20ES%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2.md)
505505
[下一篇: 7.OpenGL ES着色器语言GLSL](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/7.OpenGL%20ES%E7%9D%80%E8%89%B2%E5%99%A8%E8%AF%AD%E8%A8%80GLSL.md)
506506

507507
---

0 commit comments

Comments
 (0)