OpenGL(Open Graphics Library)是一个跨编程语言、跨平台的编程图形程序接口,主要用于图像的渲染。Android提供了简化版的OpenGL接口,即OpenGL ES。

查看系统支持的OpenGL版本

    /*** 获取支持的OpenGL版本,前16位代表最高版本,后16位代表最低版本,如0x30002,支持OpenGL 2/3*/public int getGLVersion(){ActivityManager activityManager = getSystemService(ActivityManager.class);ConfigurationInfo info = activityManager.getDeviceConfigurationInfo();return info.reqGlEsVersion;}

OpenGL及GLSurfaceView的初始化

Android系统提供了GLSurfaceView,在其内部做了OpenGL初始化工作,可直接使用GLSurfaceView。GLSurfaceView实际上创建了一个window,并在视图层穿了个洞,让底层的surface显示出来,与常规的View不同的是它没有动画或变形特效,因为它是window的一部分。

GLSurfaceView的初始化主要有

  • 设置EGL版本
glSurfaceView.setEGLContextClientVersion(3);
  • 设置渲染器
glSurfaceView.setRenderer(render);
  • 设置渲染模式,需要在设置渲染器之后
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

GLSurfaceView.Renderer

GLSurfaceView内部的一个接口,需要重写三个方法

  • onSurfaceCreated():surface第一次创建或画面重新resume会调用,通常用来加载着色器,以及设置清屏时的颜色:

    GLES20.glClearColor(r,g,b,a);
  • onSurfaceChanged():surface尺寸发生变化时调用,通常在这里计算坐标投影矩阵,以及设置OpenGL窗口的大小
    GLES20.glViewport(0, 0, width, height); 
  • onDrawFrame():每次绘制都会调用,主要做清屏以及绘制,如果之前设置的渲染模式是RENDERMODE_WHEN_DIRTY,则需要调用
    surfaceView.requestRender(),然后才会走这个方法
    @Overridepublic void onDrawFrame(GL10 gl) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);//清屏if (surfaceTexture != null) {surfaceTexture.updateTexImage();}shaderElement.draw();//绘制着色器元素}

着色器(Shader)

Android中的OpenGL支持顶点着色器(VertexShader)和片元着色器(FragmentShader)。通常在res/raw中保存着色器程序(xx.glsl),建议在android studio中下载glsl的插件。

VertexShader

用来处理图形每个顶点变换,包括旋转、平移、投影等,下面例子是顶点着色器程序vertex.glsl

#version 300 es
in vec4 verTexPosition;//顶点向量,数据来自java数组,只读
in vec4 textureCoordinate;//纹理的向量
uniform mat4 textureMatrix;//与surfaceTexture相关联的纹理坐标变换矩阵,一致变量,在着色器执行期间是不变的,与片段着色器共享
uniform mat4 projectionMatrix;//坐标投影矩阵
out vec2 aCoor;//顶点着色器的输出,作为片段着色器的输入
out float weights[9];
out vec2 coordinates[9];void main() {gl_Position=projectionMatrix*verTexPosition;aCoor=(textureMatrix*textureCoordinate).xy;
}

上面代码是OpenGL3.0的写法,与2.0有所区别;

gl_Position为内置变量,表示顶点的位置

FragmentShader

计算纹理的颜色并填充,片元着色器有多个,每个可以理解为一个点。

相机输出到surface采用的是外部纹理

samplerExternalOES
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;
in vec2 aCoor;
out vec4 gl_FragColor;
uniform samplerExternalOES fragmentSampler;
void main() {gl_FragColor=texture(fragmentSampler, aCoor);//采样函数texture()
}
gl_FragColor为内置变量,表示输出的颜色;
其它的纹理一般是用sampler2D,结合采样函数texture()输出纹理颜色

加载着色器程序

    private static int loadShader(int type, @RawRes int resId) {int shaderId = GLES20.glCreateShader(type);//创建shaderGLES20.glShaderSource(shaderId, readCodes(resId));//加载glsl代码GLES20.glCompileShader(shaderId);//编译shaderint[] status = new int[1];GLES20.glGetShaderiv(shaderId, GLES20.GL_COMPILE_STATUS, status, 0);if (status[0] != GLES20.GL_TRUE) {Log.e(TAG, "loadShader: failed, type=" + type + " message=" + GLES20.glGetShaderInfoLog(shaderId));GLES20.glDeleteShader(shaderId);return -1;}return shaderId;}/*** 加载着色器程序* @param vid vertex shader的资源id* @param fid fragment shader的资源id* @return OpenGL的programId,可以用来查找着色器程序的变量位置*/public static int loadProgram(@RawRes int vid, @RawRes int fid) {int vShaderId = loadShader(GLES20.GL_VERTEX_SHADER, vid);//顶点着色器int fShaderId = loadShader(GLES20.GL_FRAGMENT_SHADER, fid);//片段着色器int program = GLES20.glCreateProgram();if (vShaderId != -1) {GLES20.glAttachShader(program, vShaderId);//指定要附加的着色器对象}if (fShaderId != -1) {GLES20.glAttachShader(program, fShaderId);}GLES20.glLinkProgram(program);int[] status = new int[1];GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);if (status[0] != GLES20.GL_TRUE) {throw new RuntimeException("program link failed! reason=" + GLES20.glGetProgramInfoLog(program));}return program;}

从res中读取glsl的字符串,并加载glsl代码,并编译shader,这里可以封装一个帮助类。

OpenGL相关常用的java API

获取glsl中的变量位置:

int locationA=GLES20.glGetAttribLocation(programId,name);//获取attribute变量的位置,OpenGL3对应是in
int locationU=GLES20.glGetUniformLocation(programId, name1);//获取uniform变量的位置

创建buffer,用来存放要传给着色器的数组,通常包括顶点数组、纹理数组、颜色数组

    private FloatBuffer createBuffer(float[] arr) {FloatBuffer buffer = ByteBuffer.allocateDirect(arr.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(arr);buffer.position(0);return buffer;}

创建纹理并设置参数

    protected int createTexture() {//generate texture and set paramsint[] texture = new int[1];glGenTextures(texture.length, texture, 0);int target = forCamera ? GLES11Ext.GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;glBindTexture(target, texture[0]);//设置纹理参数glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//缩小,最近邻过滤glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//放大,双线性过滤glTexParameteri(target, GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);glTexParameteri(target, GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);glBindTexture(target, 0);return texture[0];}

指定使用的着色器

glUseProgram(programId);

设置attribute变量的值

 glEnableVertexAttribArray(location);glVertexAttribPointer(location, size, GL_FLOAT, false, 0, buffer);//size是每个元素的大小,比如二维坐标,就是2

设置uniform变量的值

glUniform1f(highLocation, 1f);//float 类型
glUniform1i(extSampYLocation, 3);//int 类型
glUniform4f(rectLocation, left, top, right, bottom);//float 数组
glUniformMatrix3fv(location, 1, true, matrix, 0);//矩阵传值

传递大数据量的数据,可以使用纹理的方式

glActiveTexture(GL_TEXTURE2);//之前的纹理已绑定到TEXTURE2
Buffer buffer = ByteBuffer.allocateDirect(table.length).put(table).position(0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, table.length / 3, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);

特别注意:向着色器程序传递数据,或者读取数据,只能在GL渲染线程进行,因此传值时通常是

surfaceView.queueEvent(runnable);

绘制图形:OpenGL ES 只支持点、线和三角形绘制,矩形可以用多个三角形组成

glDrawArrays(GL_TRIANGLE_STRIP, 0, count);

着色器元素的绘制,大概是这样

public void draw() {glUseProgram(programId);/*bindAttribureData(vetexLocation, vertexSize, vertexBuffer);//顶点,之前已绑定,忽略bindAttribureData(textureLocation, textureSize, textureBuffer);//纹理bindAttribureData(colorLocation, colorSize, colorBuffer);//颜色*/glUniformMatrix4fv(projectionMatrixLocation, 1, false, projectionMatrix, 0);//投影矩阵glUniformMatrix4fv(textureMatrixLocation, 1, false, textureMatrix, 0);//纹理矩阵glActiveTexture(GL_TEXTURE0);//选择当前活跃的纹理单元glBindTexture(GL_TEXTURE_2D, textureId);glUniform1i(samplerLocation, 0);//对应GL_TEXTURE0int count = vertexBuffer.capacity() / vertexSize;glDrawArrays(GL_TRIANGLE_STRIP, 0, count);glBindTexture(GL_TEXTURE_2D, 0);//取消之前绑定的纹理}

结合上面onDrawFrame()中的清屏操作,基本就完整了。

Android中的OpenGL使用初探相关推荐

  1. 在Android中使用OpenGL ES开发第(五)节:GLSL基础语法

    一.前期基础储备 笔者之前的四篇文综述了Android中使用OpenGL ES绘制基本图形和实现了简单的相机预览,初次接触OpenGL ES开发的读者可能对其中新的概念比较迷惑,尤其是其中的顶点着色器 ...

  2. 在 Android 中使用 OpenGL

    Android 通过 OpenGL 包含了对高性能 2D 和 3D 图形的支持,特别是 OpenGL ES API.OpenGL 是一个跨平台的图形 API,它为 3D 图形处理硬件规定了一个标准的软 ...

  3. android opengl版本太低,如何提高android中的opengl es显示性能

    我正在努力提高Android视频会议项目的视频显示效率.视频显示以本机opengl代码实现. opengl代码以opengl版本1的原生实现.下面给出的代码用于显示视频的每个帧. int ofi_vc ...

  4. android绘制过程3d图形,Android开发之OpenGL绘制三维图形的流程

    从这篇文章开始,接下来会连载一系列的OpenGL相关博文,好好探讨如何在Android中进行OpenGL开发. OpenGL的全称是"Open Graphics Library", ...

  5. cocos2d-x 2.X for Android中需要使用OpenGL ES 2.0

    cocos2d-x 2.X for Android中需要使用OpenGL ES 2.0 到了2.X版本中,cocos2d-x for Android已经不再支持(或者说放弃支持)opengl es 1 ...

  6. Android中实现Launcher功能之四---滑屏初探 scrollTo 以及 scrollBy方法使用说明

     本文原创 ,转载必须注明出处 :http://blog.csdn.net/qinjuning 今天给大家介绍下Android中滑屏功能的一个基本实现过程以及原理初探,最后给大家重点讲解View视图中 ...

  7. Android 中opengl es灯光效果实例

    一.还是要准备一张图片,放在res/drawable中 二.灯光效果代码: /*** 设置灯光*///设置环境光gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT ...

  8. 【OpenGL】Android 中的 skia 和 OpenGL ES

    Android Graphic : apk and Skia/OpenGL|ES Android apk 里面的画图分为2D和3D两种:2D是由Skia 来实现的,也就是我们在框架图上看到的SGL,S ...

  9. 关于openGL, openGL ES, openVG及android中2D调用关系的报告

    关于openGL, openGL ES, openVG及android中2D调用关系的报告 http://blog.chinaunix.net/u3/99423/showart_2203591.htm ...

最新文章

  1. name 'false' is not defined
  2. stm8s003 8K空间不够用,出现报错,修改stvd参数进行最优化
  3. SpringCloud学习笔记:SpringCloud简介(1)
  4. C++ —— C++运算符与表达式
  5. C++使用socket实现进程通信
  6. 用C#把文件转换为XML
  7. 如何为curl命令添加数据?
  8. uwp - ContentDialog - 自定义仿iphone提示框,提示框美化
  9. poj 1679(次小生成树)
  10. 网线制作ppt_ppt模板网线
  11. 网络协议抓包分析与爬虫入门
  12. 每月一书(202101):《财富自由之路》-李笑来
  13. 专访当当网张亮:深度解读分布式作业调度框架elastic-job
  14. 在线读书——孙天泽(嵌入式设计及Linux驱动开发指南——基于ARM9处理器)
  15. QNAP 威联通 NAS的个人使用经验 篇二:QTS系统各功能讲解
  16. 共享充电宝之争:胜于专利,败于骂街 | 一点财经
  17. python 爬去拉钩测试招聘信息
  18. 【word 应用篇】word如何插入页码以及word插入图片显示不全的解决方法
  19. 做梦都想复习的网络编程
  20. 简述工业机器人示教再现的一般步骤_工业机器人示教与初识编程语言

热门文章

  1. 2020-11-25 多行文本或段落的折叠与展开
  2. oracle登陆不了账号被锁定,轻松解决数据库账号被锁定问题
  3. mac安装pygraphviz找不到头文件
  4. PAT乙级1025题解
  5. [Cocos Creator] 制作简版消消乐(三):实现方块的生成与交换
  6. kingcms标签大全
  7. opencv-Python 目标跟踪(一)《Meanshift算法、Camshift算法》
  8. sqlserver还原.bak文件
  9. XAMPP+PhpStorm
  10. Matlab中图文本中的希腊字母和特殊字符