OpenGL和OpenGLES简介

这里先简单介绍下OpenGL和OpenGLES。OpenGL(Open Graphics Library)意为开放图形库,是一个跨平台的图形API,用于指定3D图形处理硬件中的软硬件编程接口。OpenGL一般用于图形工作站,PC端使用。由于性能和可移植性等各方面原因,在移动端使用起来相对比较麻烦。为此,Khronos公司就为OpenGL提供一个子集,OpenGL ES(OpenGL for Embedded System)。OpenGL ES是免费的跨平台且功能完善的2D/3D图形库接口API,是OpenGL的一个子集。
        在Android端使用OpenGL ES的过程中,GLSurfaceView就扮演者一个重要的角色。本篇博文将结合几个简单的案例分别介绍GLSurfaceView的基本使用以及如何使用GLSurfaceView.Renderer所提供的接口将图形绘制到SurfaceView中

GLSurfaceView的特点

  • GLSurfaceView继承SurfaceView,并实现了SurfaceHolder.Callback2接口。既然继承于SurfaceView,就拥有SurfaceView的特性。如能在View的基础上创建独立的Surface,拥有SurfaceHolder来管理Surface,并且可以在子线程中进行View的渲染操作。通过SurfaceHolder得到Canvas,然后在单独的线程中利用Canvas绘制内容,然后更新到Surface。
  • GLSurfaceView在SurfaceView的基础上实现GLThread(EGLContext创建GL环境所在线程),可通过OpenGL进行绘制,可在SurfaceView所提供的Surface进行绘制

GLSurfaceView的使用步骤

1.在使用OpenGL ES前,需要在AndroidManifest.xml中设置OpenGL ES的版本,这里我们使用的是OpenGL ES2.0,因此可进行如下声明。

   <uses-feature android:glEsVersion="0x00020000" android:required="true" /> 

2.在Activity的onCreate方法中对GLSurfaceView进行初始化,设置相关配置信息

        glSurfaceView = (GLSurfaceView) findViewById(R.id.glSurfaceView);//GLContext设置OpenGLES2.0glSurfaceView.setEGLContextClientVersion(2);// 在setRenderer之前,可以调用以下方法进行EGL设置
//        glSurfaceView.setEGLConfigChooser(true);//颜色,深度,模板等等设置
//        glSurfaceView.setEGLWindowSurfaceFactory(new GLSurfaceView.EGLWindowSurfaceFactory() {   //窗口设置
//            @Override
//            public EGLSurface createWindowSurface(EGL10 egl10, EGLDisplay eglDisplay, EGLConfig eglConfig, Object o) {
//                return null;
//            }
//
//            @Override
//            public void destroySurface(EGL10 egl10, EGLDisplay eglDisplay, EGLSurface eglSurface) {
//
//            }
//        });glSurfaceView.setRenderer(new TriangleRender());/*渲染方式,RENDERMODE_WHEN_DIRTY表示被动渲染,只有在调用requestRender或者onResume等方法时才会进行渲染。RENDERMODE_CONTINUOUSLY表示持续渲染*/glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
  1. 在Activity或者Fragment的onResume方法和onPause方法中,分别调用GLSurfaceView的onResume和onPause方法。
    @Overrideprotected void onResume() {super.onResume();glSurfaceView.onResume();}@Overrideprotected void onPause() {super.onPause();glSurfaceView.onPause();}
  1. 编写渲染器定义,实体类实现GLSurfaceView.Renderer接口,并实现onSurfaceCreated ,onDrawFrame,onSurfaceChanged方法,GLSurfaceView的渲染工作主要由GLSurfaceView.Renderer负责渲染。
public class BackgroundRender extends BaseRenderer implements GLSurfaceView.Renderer {private String TAG = BackgroundRender.class.getSimpleName();@Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {//surface被创建后需要做的处理//Set the background frame colorGLES20.glClearColor(0.0f,0.0f,0.0f,1.0f);}@Overridepublic void onSurfaceChanged(GL10 gl10, int width, int height) {// 渲染窗口大小发生改变或者屏幕方法发生变化时候回调GLES20.glViewport(0,0,width,height);}@Overridepublic void onDrawFrame(GL10 gl10) {//执行渲染工作//Redraw background colorGLES20.glClearColor(GLES20.GL_COLOR_BUFFER_BIT,0f,0f,0f);}
}

效果如下:给GLSurfaceView渲染一层黑色背景

用OpenGL在GLSurfaceView上绘制几何图形

绘制几何图形,需要将顶点坐标转为ByteBuffer,这样OpenGL才能进行图形处理。绘制三角形和正方形都需要加载顶点着色器和片元着色器的相关配置,关于着色器后面的博文会有相应介绍。这里我们定义BaseRenderer,在里面定义loadShader
方法用于创建,加载和编译对应的着色器配置信息。绘制其他形状的渲染器都继承BaseRenderer。

三角形图形绘制

public class TriangleRender extends BaseRenderer implements GLSurfaceView.Renderer {private int mProgram;private FloatBuffer vertexBuffer;private final String vertexShaderCode ="attribute vec4 vPosition;" +"void main() {" +"  gl_Position = vPosition;" +"}";private final String fragmentShaderCode ="precision mediump float;" +"uniform vec4 vColor;" +"void main() {" +"  gl_FragColor = vColor;" +"}";static float triangleCoords[] = {0.5f,  0.5f, 0.0f, // top-0.5f, -0.5f, 0.0f, // bottom left0.5f, -0.5f, 0.0f  // bottom right};//设置颜色,依次为红绿蓝和透明通道float color[] = { 1.0f, 0f, 0f, 1.0f };static final int COORDS_PER_VERTEX = 3;private int mPositionHandle;private int mColorHandle;//顶点个数private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;//顶点之间的偏移量private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节@Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {//将背景设置为灰色GLES20.glClearColor(0.5f,0.5f,0.5f,1.0f);//申请底层空间ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);bb.order(ByteOrder.nativeOrder());//将坐标数据转换为FloatBuffer,用以传入OpenGL ES程序vertexBuffer = bb.asFloatBuffer();vertexBuffer.put(triangleCoords);vertexBuffer.position(0);int vertexShader =  loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);//创建一个空的OpenGLES程序mProgram = GLES20.glCreateProgram();//将顶点着色器加入到程序GLES20.glAttachShader(mProgram,vertexShader);//将片元着色器加入到程序中GLES20.glAttachShader(mProgram,fragmentShader);//连接到着色器程序GLES20.glLinkProgram(mProgram);}@Overridepublic void onSurfaceChanged(GL10 gl10, int width, int height) {GLES20.glViewport(0,0,width,height);}@Overridepublic void onDrawFrame(GL10 gl10) {//将程序加入到OpenGLES2.0环境GLES20.glUseProgram(mProgram);//获取顶点着色器的vPosition成员句柄mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");//启用三角形顶点的句柄GLES20.glEnableVertexAttribArray(mPositionHandle);//准备三角形的坐标数据GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false,vertexStride, vertexBuffer);//获取片元着色器的vColor成员的句柄mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");//设置绘制三角形的颜色GLES20.glUniform4fv(mColorHandle, 1, color, 0);//绘制三角形GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);//禁止顶点数组的句柄GLES20.glDisableVertexAttribArray(mPositionHandle);}
}

这是定义TriangleRender继承BaseRenderer并实现GLSurfaceView.Renderer接口在GLSurfaceView上进行绘制三角形操作,只需将GLSurfaceView的Renderer设置为TriangleRender即可

glSurfaceView.setRenderer(new TriangleRender());

运行效果如下

绘制正方形

public class Square extends BaseRenderer implements GLSurfaceView.Renderer {private FloatBuffer vertexBuffer;private ShortBuffer indexBuffer;private final String vertexShaderCode ="attribute vec4 vPosition;" +"uniform mat4 vMatrix;"+"void main() {" +"  gl_Position = vMatrix*vPosition;" +"}";private final String fragmentShaderCode ="precision mediump float;" +"uniform vec4 vColor;" +"void main() {" +"  gl_FragColor = vColor;" +"}";private int mProgram;static final int COORDS_PER_VERTEX = 3;static float triangleCoords[] = {-0.5f,  0.5f, 0.0f, // top left-0.5f, -0.5f, 0.0f, // bottom left0.5f, -0.5f, 0.0f, // bottom right0.5f,  0.5f, 0.0f  // top right};static short index[]={0,1,2,0,2,3};private int mPositionHandle;private int mColorHandle;private float[] mViewMatrix=new float[16];private float[] mProjectMatrix=new float[16];private float[] mMVPMatrix=new float[16];//顶点个数private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;//顶点之间的偏移量private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节private int mMatrixHandler;//设置颜色,依次为红绿蓝和透明通道float color[] = { 1.0f, 0f, 0f, 1.0f };@Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);bb.order(ByteOrder.nativeOrder());vertexBuffer = bb.asFloatBuffer();vertexBuffer.put(triangleCoords);vertexBuffer.position(0);ByteBuffer cc= ByteBuffer.allocateDirect(index.length*2);cc.order(ByteOrder.nativeOrder());indexBuffer=cc.asShortBuffer();indexBuffer.put(index);indexBuffer.position(0);int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);//创建一个空的OpenGLES程序mProgram = GLES20.glCreateProgram();//将顶点着色器加入到程序GLES20.glAttachShader(mProgram, vertexShader);//将片元着色器加入到程序中GLES20.glAttachShader(mProgram, fragmentShader);//连接到着色器程序GLES20.glLinkProgram(mProgram);}@Overridepublic void onSurfaceChanged(GL10 gl10, int width, int height) {
//计算宽高比float ratio=(float)width/height;//设置透视投影Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7);//设置相机位置Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);//计算变换矩阵Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);}@Overridepublic void onDrawFrame(GL10 gl10) {//将程序加入到OpenGLES2.0环境GLES20.glUseProgram(mProgram);//获取变换矩阵vMatrix成员句柄mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");//指定vMatrix的值GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);//获取顶点着色器的vPosition成员句柄mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");//启用三角形顶点的句柄GLES20.glEnableVertexAttribArray(mPositionHandle);//准备三角形的坐标数据GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false,vertexStride, vertexBuffer);//获取片元着色器的vColor成员的句柄mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");//设置绘制三角形的颜色GLES20.glUniform4fv(mColorHandle, 1, color, 0);//绘制三角形
//        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);//索引法绘制正方形GLES20.glDrawElements(GLES20.GL_TRIANGLES,index.length, GLES20.GL_UNSIGNED_SHORT,indexBuffer);//禁止顶点数组的句柄GLES20.glDisableVertexAttribArray(mPositionHandle);}
}

将Square作为渲染器设置到GLSurfaceView中

glSurfaceView.setRenderer(new Square());

运行效果如下

三角形图形绘制

一个颜色是不是太单调了些呢?接下来我们绘制一个彩色三角形。基于上面的代码,我们只需做如下调整
1.修改着色器代码
2.将颜色值修改为float数组并转为floatBuffer
3.将获取的floatBuffer传递给顶点着色器
修改着色器代码如下:

private final String vertexShaderCode ="attribute vec4 vPosition;" +"uniform mat4 vMatrix;"+"varying  vec4 vColor;"+"attribute vec4 aColor;"+"void main() {" +"  gl_Position = vMatrix*vPosition;" +"  vColor=aColor;"+"}";private final String fragmentShaderCode ="precision mediump float;" +"varying vec4 vColor;" +"void main() {" +"  gl_FragColor = vColor;" +"}";

接下来我们进行数据转换:

//设置颜色float color[] = {0.0f, 1.0f, 0.0f, 1.0f ,1.0f, 0.0f, 0.0f, 1.0f,0.0f, 0.0f, 1.0f, 1.0f};ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);bb.order(ByteOrder.nativeOrder());vertexBuffer = bb.asFloatBuffer();vertexBuffer.put(triangleCoords);vertexBuffer.position(0);

最后我们需要获取着色器的句柄并设置着色器的颜色

@Overridepublic void onDrawFrame(GL10 gl10) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT| GLES20.GL_DEPTH_BUFFER_BIT);//将程序加入到OpenGLES2.0环境GLES20.glUseProgram(mProgram);//获取变换矩阵vMatrix成员句柄mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");//指定vMatrix的值GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);//获取顶点着色器的vPosition成员句柄mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");//启用三角形顶点的句柄GLES20.glEnableVertexAttribArray(mPositionHandle);//准备三角形的坐标数据GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false,vertexStride, vertexBuffer);//获取片元着色器的vColor成员的句柄mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");//设置绘制三角形的颜色GLES20.glEnableVertexAttribArray(mColorHandle);GLES20.glVertexAttribPointer(mColorHandle,4,GLES20.GL_FLOAT,false,0,colorBuffer);//绘制三角形GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);//禁止顶点数组的句柄GLES20.glDisableVertexAttribArray(mPositionHandle);}

运行效果如下:

完整Demo地址:GitHub地址 喜欢给个Star 谢谢

Android GLSurfaceView用法解析相关推荐

  1. android layoutparams,Android LayoutParams用法解析

    ViewGroup.LayoutParams介绍 LayoutParams携带了子控件针对父控件的信息,告诉父控件如何放置自己 LayoutParams类也只是简单的描述了宽高,宽和高都可以设置成三种 ...

  2. Android Volley完全解析1:初识Volley的基本用法

    原文链接:http://blog.csdn.net/guolin_blog/article/details/17482165,CSDN 郭霖 1. Volley简介 我们平时在开发Android应用的 ...

  3. Android Volley完全解析(一),初识Volley的基本用法 转载地址:http://blog.csdn.net/guolin_blog/article/details/17482095

    转载地址:http://blog.csdn.net/guolin_blog/article/details/17482095 1. Volley简介 我们平时在开发Android应用的时候不可避免地都 ...

  4. Android Volley完全解析(一),初识Volley的基本用法

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482095 1. Volley简介 我们平时在开发Android应用的时候不可避 ...

  5. 四种Java线程池用法解析

    四种Java线程池用法解析 本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 ...

  6. Android ActionBar完全解析,使用官方推荐的最佳导航栏(下) .

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/25466665 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工 ...

  7. Android源码解析(一)动画篇-- Animator属性动画系统

    Android源码解析-动画篇 Android源码解析(一)动画篇-- Animator属性动画系统 Android源码解析(二)动画篇-- ObjectAnimator Android在3.0版本中 ...

  8. Android ActionBar完全解析,使用官方推荐的最佳导航栏(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/25466665 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工 ...

  9. Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)

    本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/guide/topics/ui/act ...

最新文章

  1. vi 环境,跳转函数定义
  2. 采集/自动登录啊都可以用这两个方法实现 asp.net
  3. 像素位移_1亿像素放大也清晰 OPPO Ace2超清四摄解析
  4. linux mysql插入中文乱码_解决Linux下Tomcat向MySQL插入数据中文乱码问题
  5. LeetCode 1019. 链表中的下一个更大节点(单调栈)
  6. 怎样能确保计算机安全,如何确保电脑安全
  7. msvcrt python linux,Python msvcrt.CrtSetReportMode方法代码示例
  8. 文件没有后缀名,如何批量添加为.jpg
  9. [GCN+FocalLoss] 从数据角度分析实验 of Semi-supervised classification with graph convolutional networks
  10. python绘制小猪佩奇
  11. 两个工作流:什么时候选择BizTalk,什么时候选择WWF?微软人士给了一个简单的判断原则...
  12. 三个linux系统共存,修改默认启动
  13. 用美图秀秀批量修改图像尺寸分辨率大小、批量修改名字
  14. 再谈PHP从入门到精通需要几年
  15. C语言 矩阵相似度
  16. 软件工程基础篇(五):结构化程序分析SA+结构化程序设计SP+详细设计
  17. 【Unity实战100例】Unity幸运大转盘之概率可控
  18. 火狐主页被360导航篡改(360安全卫士中的主页防护导致的)
  19. 【论文】Track to Detect and Segment: An Online Multi-Object Tracker
  20. 阿里云服务器建站教程

热门文章

  1. 学Python真的能赚钱吗?
  2. ant design vue input change_ElementUI 不维护了?供我们选择的 Vue 组件库还有很多!
  3. html让图标替代回退按钮,9款精美别致的CSS3菜单和按钮
  4. Android引导蒙层,安卓新手引导图,引导图层,支持椭圆,圆形,矩形多种形状,一行代码快速搞定
  5. centos7设置static时,无法连接网络
  6. oracle 中的cast函数,Oracle cast函数对用户数据进行类型转换
  7. 详解python列表中冒号的用法
  8. sqlserver 多表联合查询
  9. pandas提取数据框其中几列生成新数据框
  10. Linux下压缩文件夹命令