OpenGLES Android篇零基础系列(一):OpenGLES2.x可渲染管道基本流程

2024-05-31 14:18

本文主要是介绍OpenGLES Android篇零基础系列(一):OpenGLES2.x可渲染管道基本流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载请注明出处

前言

OpenGL ES是OpenGL的一个子集,是针对手机、PDA和游戏主机等嵌入式设备而设计的。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
因此OpenGL ES作为第三方库被应用在android中。
到目前为止,OpenGL ES已经发展有了3个版本,OpenGL ES 1.0 , OpenGL ES 2.0 , OpenGL ES 3.0。其中OpenGL ES 1.0 是以OpenGL 1.3规范为基础,OpenGL ES 2.0 是以OpenGL 2.0 为基础,OpenGL ES 3.0是移动设备专用,以OpenGL 4.3为标准。

值得注意的是,在OpenGL2.0以前,OpenGL用的都是固定管道。之后就改为可渲染管道了,
所谓固定管道,就是固定工序,固定流程,以开关的形式开发出来供开发者调用,要实现什么功能,开发者得自己去考虑这些开关之间的组合形式,效率很低。
而渲染管道,就弥补了固定管道的缺点,它自由度高,可通过编程来实现功能,效率在大提高。因此这也是为什么在2.xAPI中删除了以前的一些固定管道的API。

因此,本文将结合一个例子,具体看一下可渲染管道怎么编程。

正文:如何利用OpenGL ES 2.0可渲染管道来创建简单的三角图形

第一步:创建GLSurfaceView对象

【说明】:
GLSurfaceView 是为OpenGL专门定义的一个类,它继承自SurfaceView。因此包含SurfaceView的一切特性。同时,它也增加了用于OpenGL特有的一些方法,比如:setRender(Render render)等。
想探究GLSurfaceView渲染过程的同学,可以去官网看看。

获取GLSurfaceView对象的途径有2种,可以直接在xml中写,也可以在代码中new。
本文我们选用后一种,eg:

public class SunnyOpenGLActivity extends FragmentActivity {private GLSurfaceView mGLSurfaceView;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);initView();setContentView(mGLSurfaceView);}@Overrideprotected void onResume() {super.onResume();mGLSurfaceView.onResume();}@Overrideprotected void onPause() {super.onPause();mGLSurfaceView.onPause();}private void initView() {mGLSurfaceView = new GLSurfaceView(this);}
第二步:自定义Render类实现GLSurfaceView.Render接口

这一步是最重要的一步,因为着色器的生成,矩阵的变换,纹理的加载等都是在这里实现的,GLSurfaceView.Render有三个重要的待实现的接口:
onSurfaceCreated(GL10 glUnused,EGLConfig config);
onSurfaceChanged(GL10 glUnused,int width,int height);
onDrawFrame(GL10 glUnused);

以上三个方法回调的时机分别如下:

方法登时调用
onSurfaceCreated当GLSurfaceView 实例生成时回调;
onSurfaceChanged当手机横/竖屏切换时回调;
onDrawFrame是由系统自动回调的,它会以一定的帧频率来调用重绘View。

当设置GLSurfaceView的渲染模式为GLSurfaceView.RENDERMODE_CONTINUOUSLY或不设置时,系统就会主动渲染,就会回调onDrawFrame()方法,
如果设置为 RENDERMODE_WHEN_DIRTY ,则还得手动调用requestRender(),才会渲染。

自定义SunnyGLRender类如下:

public class SunnyGLRender implements GLSurfaceView.Renderer {private int mProgram;private int maPostionHandle;private FloatBuffer mTriangleVB;//定义顶点(vertex)着色器命令语句private final String vertexShaderCode ="uniform mat4 uMVPMatrix; \n" +"attribute vec4 vPosition; \n" +"void main(){              \n" +" gl_Position = vPosition; \n" +"}                         \n";//片元着色器private final String fragmentShaderCode ="precision mediump float;\n" +"void main(){ \n" +" gl_FragColor = vec4 (0.63671875,0.76953125,0.22265625,1.0);\n" +//RGBA"}\n";//应用投影与相机视图private int muMVPMatrixHandle;//用于存储变换矩阵结果的总变换矩阵[4*4]private float[] mMVPMatrix = new float[16];//[4*4]的视图变换矩阵private float[] mVMatrix = new float[16];//[4*4]的投影变换矩阵private float[] mProjMatrix = new float[16];//[4*4]的模型变换矩阵private float[] mMMatrix = new float[16];public float mAngle;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {//GLES20:为OpenGL ES2.0版本,相应的//GLES30:OpenGL ES3.0//黑色背景GLES20.glClearColor(0.5f,0.5f,0.5f,1.0f);//glClear:清除缓冲区标志,这里为:清除颜色缓冲及深度缓冲,把整个窗口清除为黑色背景GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);initShapes();int vertextShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);//申请特定的着色器,program != 0 申请成功mProgram = GLES20.glCreateProgram();if(mProgram != 0 ){GLES20.glAttachShader(mProgram,vertextShader);GLES20.glAttachShader(mProgram,fragmentShader);//连接着色器GLES20.glLinkProgram(mProgram);int[] linkStatus = new int[1];//查看着色器连接情况GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);if (linkStatus[0] != GLES20.GL_TRUE) {//连接失败Log.e(TAG, "Could not link program: ");Log.e(TAG, GLES20.glGetProgramInfoLog(program));GLES20.glDeleteProgram(program);program = 0;}//获取着特定着色器vPosition参数。maPostionHandle = GLES20.glGetAttribLocation(mProgram,"vPosition");}}/*** 初始化三角形的一些参数*/private void initShapes() {/*** X,Y,Z三轴顶点坐标* U,V也即S,T,是图片,视频等以纹理的形式加载到GLSurfaceView中时的坐标,即纹理坐标* U,V纹理坐标是无方向的*///第一种写法:顶点坐标与纹理坐标写一起float trianlgeCoords[] = {//X,Y,Z,U,V-1.0f, -0.5f, 0, 0.0f, 0.5f,1.0f, -0.5f, 0, 1.0f, 0.5f,0.0f,  1.0f, 0, 0.5f,  0.0f};//第二种写法:顶点坐标与纹理坐标分开写:(因为Z为0,只考虑二维平面,)float veticsCoor[] = {//X,Y-1.0f,-0.5f,1.0f,-0.5f,0.0f,1.0f,};float textureCoor[] = {//U,V0.0f,0.5f,1.0f,0.5f,0.5f,0.0,};//把顶点坐标存入Buffer中ByteBuffer vbb = ByteBuffer.allocateDirect(trianlgeCoords.length * 4);vbb.order(ByteOrder.nativeOrder());mTriangleVB = vbb.asFloatBuffer();mTriangleVB.put(trianlgeCoords);mTriangleVB.position(0);}/*** 加载指定着色器* @param type* @param shaderCode* @return*/private int loadShader(int type,String shaderCode){int shader = GLES20.glCreateShader(type);if(shader != 0 ){//加载着色器脚本程序(即本例的String 变量命令语句)//我们也可以把顶点着色器与片元着色器以文件的形式加载GLES20.glShaderSource(shader,shaderCode);//编译着色器脚本程序GLES20.glCompileShader(shader);//因为GLSL不能像我们写Java或C等,可以debug或Log调试,//这里我们就只能通过其返回的值,来判断是否编译通过,//如果编译失败,则检查GLSL是否写正确。//在写GLSL时,一定要检查参数类型,比如:vec2等2个浮点数的类型是否写成vec3或vec4等了,int[] compiled = new int[1];//查看编译结果GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);if (compiled[0] == 0) {//编译失败,释放申请的着色器GLES20.glDeleteShader(shader);shader = 0;}} return shader;}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {//给定窗口大小GLES20.glViewport(0, 0, width, height);//float ratio = (float) width/height;//调用此方法来计算生成透视投影矩阵Matrix.frustumM(mProjMatrix,0,-ratio,ratio,-1,1,3,7);//当Sucrface改变时,获取指定着色器的uMVPMatrix参数muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,"uMVPMatrix");//设定相机的视角//调用此方法产生摄像机9参数位置矩阵Matrix.setLookAtM(mVMatrix,0,0,0,-3, //相机的x,y,z坐标0,0,0,//目标对应的x,y,z坐标0,1.0f,1.0f//相机的视觉向量(upx,upy,upz,三个向量最终的合成向量的方向为相机的方向));}@Overridepublic void onDrawFrame(GL10 gl) {// Redraw background color//把左矩阵投影矩阵与右矩阵视图矩阵变换后的结果存储在总矩阵mMVPMatrix中Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,mVMatrix,0);//为三角形创建一个旋转动作/*long time = SystemClock.uptimeMillis() % 4000L;mAngle = 0.090f * ((int)time);*///创建一个绕x,y,z轴旋转一定角度的矩阵Matrix.setRotateM(mMMatrix,0,mAngle,0,0,1.0f);Matrix.multiplyMM(mMVPMatrix,0,mVMatrix,0,mMMatrix,0);Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,mMVPMatrix,0);GLES20.glUniformMatrix4fv(muMVPMatrixHandle,1,false,mMVPMatrix,0);//把Program用到OpenGL环境中GLES20.glUseProgram(mProgram);//准备画三角形的数据//为指定着色器取出的参数赋值   GLES20.glVertexAttribPointer(maPostionHandle,3,GLES20.GL_FLOAT,false,12,mTriangleVB);//使用这个从指定着色器中取出的参数的值GLES20.glEnableVertexAttribArray(maPostionHandle);//开始画GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);}
}
第三步:权限声明

经过以上二步,程序还不能运行,得在AndroidManifest.xml中声明相应权限。

<!-- Tell the system this app requires OpenGL ES 2.0. --><uses-feature
        android:glEsVersion="0x00020000"android:required="true" />

运行程序 就可以看到三角形了。

下一节

参考资料

Android OpenGL ES2.0 开发文档
Android OpenGL ES 应用(二) 纹理
浅学OpenGLES2.0
google ApiDemo(这个自己看官方Demo就好了,就没有贴出下载地址了)

这篇关于OpenGLES Android篇零基础系列(一):OpenGLES2.x可渲染管道基本流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1018164

相关文章

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

使用Python进行文件读写操作的基本方法

《使用Python进行文件读写操作的基本方法》今天的内容来介绍Python中进行文件读写操作的方法,这在学习Python时是必不可少的技术点,希望可以帮助到正在学习python的小伙伴,以下是Pyth... 目录一、文件读取:二、文件写入:三、文件追加:四、文件读写的二进制模式:五、使用 json 模块读写

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

MySQL中my.ini文件的基础配置和优化配置方式

《MySQL中my.ini文件的基础配置和优化配置方式》文章讨论了数据库异步同步的优化思路,包括三个主要方面:幂等性、时序和延迟,作者还分享了MySQL配置文件的优化经验,并鼓励读者提供支持... 目录mysql my.ini文件的配置和优化配置优化思路MySQL配置文件优化总结MySQL my.ini文件

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica