Android中的OpenGL使用初探
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使用初探相关推荐
- 在Android中使用OpenGL ES开发第(五)节:GLSL基础语法
一.前期基础储备 笔者之前的四篇文综述了Android中使用OpenGL ES绘制基本图形和实现了简单的相机预览,初次接触OpenGL ES开发的读者可能对其中新的概念比较迷惑,尤其是其中的顶点着色器 ...
- 在 Android 中使用 OpenGL
Android 通过 OpenGL 包含了对高性能 2D 和 3D 图形的支持,特别是 OpenGL ES API.OpenGL 是一个跨平台的图形 API,它为 3D 图形处理硬件规定了一个标准的软 ...
- android opengl版本太低,如何提高android中的opengl es显示性能
我正在努力提高Android视频会议项目的视频显示效率.视频显示以本机opengl代码实现. opengl代码以opengl版本1的原生实现.下面给出的代码用于显示视频的每个帧. int ofi_vc ...
- android绘制过程3d图形,Android开发之OpenGL绘制三维图形的流程
从这篇文章开始,接下来会连载一系列的OpenGL相关博文,好好探讨如何在Android中进行OpenGL开发. OpenGL的全称是"Open Graphics Library", ...
- 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 ...
- Android中实现Launcher功能之四---滑屏初探 scrollTo 以及 scrollBy方法使用说明
本文原创 ,转载必须注明出处 :http://blog.csdn.net/qinjuning 今天给大家介绍下Android中滑屏功能的一个基本实现过程以及原理初探,最后给大家重点讲解View视图中 ...
- Android 中opengl es灯光效果实例
一.还是要准备一张图片,放在res/drawable中 二.灯光效果代码: /*** 设置灯光*///设置环境光gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT ...
- 【OpenGL】Android 中的 skia 和 OpenGL ES
Android Graphic : apk and Skia/OpenGL|ES Android apk 里面的画图分为2D和3D两种:2D是由Skia 来实现的,也就是我们在框架图上看到的SGL,S ...
- 关于openGL, openGL ES, openVG及android中2D调用关系的报告
关于openGL, openGL ES, openVG及android中2D调用关系的报告 http://blog.chinaunix.net/u3/99423/showart_2203591.htm ...
最新文章
- name 'false' is not defined
- stm8s003 8K空间不够用,出现报错,修改stvd参数进行最优化
- SpringCloud学习笔记:SpringCloud简介(1)
- C++ —— C++运算符与表达式
- C++使用socket实现进程通信
- 用C#把文件转换为XML
- 如何为curl命令添加数据?
- uwp - ContentDialog - 自定义仿iphone提示框,提示框美化
- poj 1679(次小生成树)
- 网线制作ppt_ppt模板网线
- 网络协议抓包分析与爬虫入门
- 每月一书(202101):《财富自由之路》-李笑来
- 专访当当网张亮:深度解读分布式作业调度框架elastic-job
- 在线读书——孙天泽(嵌入式设计及Linux驱动开发指南——基于ARM9处理器)
- QNAP 威联通 NAS的个人使用经验 篇二:QTS系统各功能讲解
- 共享充电宝之争:胜于专利,败于骂街 | 一点财经
- python 爬去拉钩测试招聘信息
- 【word 应用篇】word如何插入页码以及word插入图片显示不全的解决方法
- 做梦都想复习的网络编程
- 简述工业机器人示教再现的一般步骤_工业机器人示教与初识编程语言