OpenGL ES是OpenGL的一个子集,它针对移动端或嵌入式系统作了部分精简,而Android系统中集成了OpenGL ES,方便咱们经过其接口充分使用GPU的计算和渲染能力。android
OpenGL ES2.0是基于可编程管线设计。相对OpenGL ES 1.x,OpenGL ES 2.0进行了大变革,更具灵活性,功能也更强大,而且渲染效率更高,效果更好。目前Android对OpenGL ES的支持以下:编程
- OpenGL ES 1.0 和 1.1 可以被Android 1.0及以上版本支持
- OpenGL ES 2.0 可以被Android 2.2及更高版本支持
- OpenGL ES 3.0 可以被Android 4.3及更高版本支持
- OpenGL ES 3.1 可以被Android 5.0及以上版本支持
相比起来学习OpenGL ES选择2.0版本是一个相对最佳的选择,能够兼容4.0以上的手机设备,而且OpenGL ES 3.x都向下兼容OpenGL ES 2.0。本系列以OPENGL ES2.0演示和开发。数组
这里主要关注OpenGL ES的这两方面能力:bash
- 摄像头预览效果处理。
- 视频处理。
Android框架里面两个基本的类来方便使用OpenGL ES API建立和操做图形: GLSurfaceView
和 GLSurfaceView.Renderer
。GLSurfaceView
是管理OpenGL surface的一个特殊的View,它能够帮助咱们把OpenGL的surface渲染到Android的View上,而且封装了不少建立OpenGL环境所须要的配置,使咱们可以更方便地使用OpenGL。框架
GLSurfaceView.Renderer
接口定义了在GLSurfaceView中绘制图形所需的方法。一般状况下咱们使用GLSurfaceView.setRenderer()
方法将此接口实现设置进GLSurfaceView
中。此接口方法主要为:ide
- onSurfaceCreated():建立GLSurfaceView时,系统调用该方法。使用此方法执行只须要执行一次的操做,如设置OpenGL环境参数或初始化OpenGL图形对象。
- onDrawFrame():系统在每次重绘GLSurfaceView时调用这个方法。使用此方法做为绘制图形时的主要方法。
- onSurfaceChanged():当GLSurfaceView的大小或设备屏幕方向发生变化时,系统调用此方法。例如:设备从纵向变为横向时,系统调用此方法。咱们应该使用此方法来响应GLSurfaceView容器的改变。
在AndroidManifest.xml文件中设置使用的OpenGL ES的版本:学习
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
复制代码
通常来讲,咱们以下建立GLSurfaceView
,设置 GLSurfaceView.Renderer
便可。接下来咱们将重点放在 GLSurfaceView.Renderer
的编写上面。ui
public class ZkGLSurfaceView extends GLSurfaceView {
public ZkGLSurfaceView(Context context) {
this(context,null);
}
public ZkGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
//使用OpenGL ES 2.0
setEGLContextClientVersion(2);
//设置Renderer
setRenderer(new MyRenderer(context));
//设置刷新模式
setRenderMode(RENDERMODE_WHEN_DIRTY);
}
}
复制代码
定点着色器this
attribute vec4 vPosition;
attribute vec2 vCoordinate;
varying vec2 aCoordinate;
void main() {
gl_Position = vPosition;
aCoordinate = vCoordinate;
}
复制代码
片元着色器spa
precision mediump float;
uniform sampler2D vTexture;
varying vec2 aCoordinate;
void main() {
gl_FragColor = texture2D(vTexture,aCoordinate);
}
复制代码
gl_Position
和gl_FragColor
都是Shader的内置变量,分别为定点位置和片元颜色。
attribute 通常用于各个顶点各不相同的量。如顶点颜色、坐标等
varying 用于vertex和fragment之间传递值,通常用于顶点着色器传递到片元着色器的量
uniform 通常用于对于3D物体中全部顶点都相同的量。好比光源位置,统一变换矩阵等
//顶点坐标
private float[] vertex = {
-1.0f,1.0f, //左上角
-1.0f,-1.0f, //左下角
1.0f,1.0f, //右上角
1.0f,-1.0f //右下角
};
private final float[] sCoord={
0f, 0f, //左上角
0f, 1f, //左下角
1f, 0f, //右上角
1f, 1f //右下角
};
//申请底层空间 将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer().put(vertex);
mVertexBuffer.position(0);
mFragmentBuffer = ByteBuffer.allocateDirect(sCoord.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer().put(sCoord);
mFragmentBuffer.position(0);
复制代码
顶点坐标和纹理坐标的环绕方向必须一致。
int vertex_shader = loadShader(GLES20.GL_VERTEX_SHADER,VERTEX_SHADER);
int fragment_shader = loadShader(GLES20.GL_FRAGMENT_SHADER,FRAGMENT_SHADER);
private int loadShader(int glVertexShader, String vertexShader) {
//建立shader(着色器:顶点或片元)
int glCreateShader = GLES20.glCreateShader(glVertexShader);
//加载shader源码并编译shader
GLES20.glShaderSource(glCreateShader, vertexShader);
int[] compiled = new int[1];
//检查是否编译成功
GLES20.glGetShaderiv(glCreateShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] != GLES20.GL_TRUE){
GLES20.glDeleteShader(glCreateShader);
return -1;
}
return glCreateShader;
}
复制代码
//建立渲染程序
mProgram = GLES20.glCreateProgram();
//将着色器程序添加到渲染程序中
GLES20.glAttachShader(mProgram, vertex_shader);
GLES20.glAttachShader(mProgram, fragment_shader);
//连接源程序
GLES20.glLinkProgram(mProgram);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE){
String info = GLES20.glGetProgramInfoLog(mProgram);
GLES20.glDeleteProgram(mProgram);
throw new RuntimeException("Could not link program: " + info);
}
复制代码
private int loadTexture(int resId){
int[] textures = new int[1];
//建立和绑定纹理
GLES20.glGenTextures(1,textures,0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
//激活第0个纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glUniform1i(mVTexture, 0);
//设置环绕和过滤方式
//环绕(超出纹理坐标范围):(s==x t==y GL_REPEAT 重复)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
//过滤(纹理像素映射到坐标点):(缩小、放大:GL_LINEAR线性)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), resId);
//设置图片
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
bitmap = null;
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
return textures[0];
}
复制代码
@Override
public void onDrawFrame() {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(1.0f, 0, 0, 1f);
//使用源程序
GLES20.glUseProgram(mProgram);
//绑定绘制纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureid);
//使顶点属性数组有效
GLES20.glEnableVertexAttribArray(mVPosition);
//为顶点属性赋值
GLES20.glVertexAttribPointer(mVPosition, 2, GLES20.GL_FLOAT, false, 8, mVertexBuffer);
GLES20.glEnableVertexAttribArray(mVCoordinate);
GLES20.glVertexAttribPointer(mVCoordinate, 2, GLES20.GL_FLOAT, false, 8, mFragmentBuffer);
//绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
复制代码
完整代码:
public class MyRenderer implements GLSurfaceView.Renderer{
private static final String VERTEX_SHADER = "attribute vec4 vPosition;\n"
+ "attribute vec2 vCoordinate;\n"
+ "varying vec2 aCoordinate;\n"
+ "void main() {\n"
+ "gl_Position = vPosition;\n"
+ "aCoordinate = vCoordinate;\n"
+ "}";
private static final String FRAGMENT_SHADER = "precision mediump float;\n"
+ "uniform sampler2D vTexture;\n"
+ "varying vec2 aCoordinate;\n"
+ "void main() {\n"
+ "gl_FragColor = texture2D(vTexture,aCoordinate);\n"
+ "}";
private float[] vertex = {
-1.0f,1.0f, //左上角
-1.0f,-1.0f, //左下角
1.0f,1.0f, //右上角
1.0f,-1.0f //右下角
};
private final float[] sCoord={
0f, 0f, //左上角
0f, 1f, //左下角
1f, 0f, //右上角
1f, 1f //右下角
};
private FloatBuffer mVertexBuffer;
private FloatBuffer mFragmentBuffer;
private int mProgram;
private int mVPosition;
private int mVCoordinate;
private int mVTexture;
private Context mContext;
private int mTextureid;
public MyRenderer(Context context){
mContext = context;
mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer().put(vertex);
mVertexBuffer.position(0);
mFragmentBuffer = ByteBuffer.allocateDirect(sCoord.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer().put(sCoord);
mFragmentBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
int vertex_shader = loadShader(GLES20.GL_VERTEX_SHADER,VERTEX_SHADER);
int fragment_shader = loadShader(GLES20.GL_FRAGMENT_SHADER,FRAGMENT_SHADER);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertex_shader);
GLES20.glAttachShader(mProgram, fragment_shader);
GLES20.glLinkProgram(mProgram);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE){
String info = GLES20.glGetProgramInfoLog(mProgram);
GLES20.glDeleteProgram(mProgram);
throw new RuntimeException("Could not link program: " + info);
}
mVPosition = GLES20.glGetAttribLocation(mProgram, "vPosition");
mVCoordinate = GLES20.glGetAttribLocation(mProgram, "vCoordinate");
mVTexture = GLES20.glGetUniformLocation(mProgram, "vTexture");
mTextureid = loadTexture(R.drawable.fengj);
}
private int loadTexture(int resId){
int[] textures = new int[1];
//建立和绑定纹理
GLES20.glGenTextures(1,textures,0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
//激活第0个纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glUniform1i(mVTexture, 0);
//设置环绕和过滤方式
//环绕(超出纹理坐标范围):(s==x t==y GL_REPEAT 重复)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
//过滤(纹理像素映射到坐标点):(缩小、放大:GL_LINEAR线性)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), resId);
//设置图片
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
bitmap = null;
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
return textures[0];
}
private int loadShader(int glVertexShader, String vertexShader) {
int glCreateShader = GLES20.glCreateShader(glVertexShader);
GLES20.glShaderSource(glCreateShader, vertexShader);
GLES20.glCompileShader(glCreateShader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(glCreateShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] != GLES20.GL_TRUE){
GLES20.glDeleteShader(glCreateShader);
return -1;
}
return glCreateShader;
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(1.0f, 0, 0, 1f);
//使用源程序
GLES20.glUseProgram(mProgram);
//绑定绘制纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureid);
//使顶点属性数组有效
GLES20.glEnableVertexAttribArray(mVPosition);
//为顶点属性赋值
GLES20.glVertexAttribPointer(mVPosition, 2, GLES20.GL_FLOAT, false, 8, mVertexBuffer);
GLES20.glEnableVertexAttribArray(mVCoordinate);
GLES20.glVertexAttribPointer(mVCoordinate, 2, GLES20.GL_FLOAT, false, 8, mFragmentBuffer);
//绘制图形
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
}
复制代码