Android Open GL ES - 绘制三角形

2024-05-06 20:48
文章标签 android es 绘制 三角形 open gl

本文主要是介绍Android Open GL ES - 绘制三角形,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

初始化GLSurfaceView

接下来我们将尝试使用OpenGLES绘制一个三角形,首先创建一个Android Studio Project,OpenGLESTriangles
接下来我们来学习初始化Open GL ESMainActivity.java内部代码如下:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);}

在Android 4.0以前我们进行Open GL渲染主要依赖于GLSurfaceView这个类,GLSurfaceView实际上创建了一个自持的独立窗体,在View层开放一个接口用于展示OpenGL Surface中的内容,因此它不像普通View一样对旋转,动画等支持的那么良好。在Android 4.0后添加了TextureView用于展示OpenGL Surface,这个View并不像GLSurfaceView一样需要创建一个单独的窗体,这里我们先学习使用GLSurfaceView
MainActivity.java中添加如下代码,用于声明GLSurfaceView对象以及记录当前设置是否支持Open GLES2.0:

private GLSurfaceView mGLSurfaceView;private boolean mRendererSet = false;

随后我们需要判断当前设置是否支持Open GL ES 2.0,如果支持,就初始化GLSurfaceView,如果不支持,就弹出Toast告知用户,具体代码如下:

 /*** help to judge whether device support open gl es version 2.0* @param context* @return true:support 2.0 version,false:do not support 2.0 version*/public static boolean isSupportOpenGLES2(Context context) {ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();return configurationInfo.reqGlEsVersion >= 0x20000 || (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH_MR1 && (Build.FINGERPRINT.startsWith(FINGERPRINT_GENERIC) || Build.FINGERPRINT.startsWith(FINGERPRINT_UNKNOWN) || Build.MODEL.contains(MODEL_GOOGLE)|| Build.MODEL.contains(MODEL_EMULATOR) || Build.MODEL.contains(MODEL_SDK)));}
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mGLSurfaceView = new GLSurfaceView(this);if (DeviceInfor.isSupportOpenGLES2(this)){mGLSurfaceView.setEGLContextClientVersion(2);mGLSurfaceView.setRenderer(new TriangleRenderer(this));mRendererSet = true;}else {Toast.makeText(this, "This Device does not support open gl es 2.0 version!", Toast.LENGTH_SHORT).show();return;}setContentView(mGLSurfaceView);}

由于GLSurfaceView是连接Open GL ESAndroid View之间的桥梁,所以它和Android组件一样,拥有完整的生命周期函数,在初始化后需要管理它的生命周期,代码如下:

@Overrideprotected void onPause() {super.onPause();if (mRendererSet){mGLSurfaceView.onPause();}}@Overrideprotected void onResume() {super.onResume();if (mRendererSet){mGLSurfaceView.onResume();}}

在完成基本的GLSurfaceView创建后,我们来了解一些关于Open Gl ES的基础知识。

Open Gl ES基础

1.在Open Gl ES中只支持三种基本图形,点,线和三角形,所有复杂图形均由这三者绘制而成。
2.在Open Gl ES中绘制图形依赖于渲染器(Renderer),在渲染器中完成图形渲染。在渲染器中使用着色器对图形的每一个位置进行着色,在Open Gl ES中有两类着色器,顶点着色器(VertexShader)和片段着色器(FragmentShader),在渲染器中通过加载,编译着色器,链接程序来完成图形渲染。
按照上文所说我们接下来定义三角形的顶点信息,以及着色器文件。

三角形与着色器(Shader)

接下来为我们的项目添加渲染器(Renderer),代码如下:

public class TriangleRenderer implements Renderer {public static final String TAG = "TriangleRenderer";private Context mContext;public TriangleRenderer(Context context) {mContext = context;}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {}@Overridepublic void onDrawFrame(GL10 gl) {}
}

在Open Gl ES中,其使用的是世界坐标系(即绝对坐标系),附图如下:
这里写图片描述
在该坐标系中,坐标原点位于屏幕中心,XYZ三轴符合右手法则,我们定义三角形的顶点信息如下(PS:不考虑Z轴):

float[] vertexTrangles = {-1.0f, -1.0f,1.0f, -1.0f,0f, 1.0f};

定义存储三角形的Buffer信息如下:

private static final int BYTES_PER_FLOAT = 4;//每个Float占四个字节
private FloatBuffer vertexData;//存储顶点数据的Buffer
private static final int POSITION_COMPONENT_COUNT = 2;//代表点坐标的个数

将上述代码写入渲染器中,在渲染器的构造函数中为三角形顶点初始化缓存大小,代码如下:

vertexData = ByteBuffer.allocateDirect(vertexTrangles.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexData.put(vertexTrangles);

随后编写Open Gl ES着色器文件,在res目录下新建raw文件夹,并新建simple_vertex_shader.glsl文件,内容如下:

attribute vec4 a_Position;
#定义一个点的位置信息
void main(){gl_Position = a_Position;
}

新建simple_fragement_shader.glsl文件,内容如下:

#数据类型
precision mediump float;
#片段着色器中的色值
uniform vec4 u_Color;void main(){gl_FragColor = u_Color;
}

加载编译Shader,链接程序

从资源文件中读取glsl文件转化成String,工具函数如下:

 /*** read glsl file from resource* @param context* @param resourceId example R.raw.vertex_shader* @return*/public static String readTextFileFromResource(Context context,int resourceId){StringBuilder body = new StringBuilder();try {InputStream inputStream = context.getResources().openRawResource(resourceId);InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String nextLine;while ((nextLine = bufferedReader.readLine()) != null){body.append(nextLine);body.append('\n');}} catch (IOException e) {e.printStackTrace();}return body.toString();}

编译着色器文件,代码如下:

public static int compileVertexShader(String shaderCode) {return compileShader(GL_VERTEX_SHADER, shaderCode);}public static int compileFragmentShader(String shaderCode) {return compileShader(GL_FRAGMENT_SHADER, shaderCode);}private static int compileShader(int type, String shaderCode) {int shaderObjectId = glCreateShader(type);if (shaderObjectId == 0) {return 0;}glShaderSource(shaderObjectId, shaderCode);glCompileShader(shaderObjectId);final int[] compileStatus = new int[1];glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);if (compileStatus[0] == 0) {glDeleteShader(shaderObjectId);return 0;}return shaderObjectId;}

随后我们在渲染器中完成程序的构建使用,核心代码如下:

 @Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {gl10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//加载Shader fileString vertexShaderSource = TextResourceReader.readTextFileFromResource(mContext, R.raw.simple_vertex_shader);String fragmentShaderSource = TextResourceReader.readTextFileFromResource(mContext, R.raw.simple_fragment_shader);//编译Shaderint vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource);//链接程序mProgramId = ShaderHelper.linkProgram(vertexShader, fragmentShader);//验证程序ShaderHelper.validateProgram(mProgramId);//使用程序glUseProgram(mProgramId);//查找颜色片元位置uColorLocation = glGetUniformLocation(mProgramId, U_COLOR);//查找顶点片元位置aPositionLocation = glGetAttribLocation(mProgramId, A_POSITION);//重置数据集位置vertexData.position(0);//读取顶点信息并渲染glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0,vertexData);glEnableVertexAttribArray(aPositionLocation);}

以上代码中的链接程序函数源码如下:

public static int linkProgram(int vertexShaderId, int fragmentShaderId) {int programId = glCreateProgram();if (programId == 0) {return 0;}//完成着色器和程序之间的绑定glAttachShader(programId, vertexShaderId);glAttachShader(programId, fragmentShaderId);//链接程序glLinkProgram(programId);final int[] linkStatus = new int[1];glGetProgramiv(programId, GL_LINK_STATUS, linkStatus, 0);if (linkStatus[0] == 0) {glDeleteProgram(programId);return 0;}return programId;}public static boolean validateProgram(int programId) {glValidateProgram(programId);final int[] validateStatus = new int[1];glGetProgramiv(programId, GL_VALIDATE_STATUS, validateStatus, 0);return validateStatus[0] != 0;}

绘制三角形

修改渲染器中代码如下:

 @Overridepublic void onSurfaceChanged(GL10 gl10, int i, int i1) {gl10.glViewport(0, 0, i, i1);}@Overridepublic void onDrawFrame(GL10 gl10) {gl10.glClear(gl10.GL_COLOR_BUFFER_BIT);//传入片元颜色值,可以通过改变最后四个参数值参看片元渲染后的颜色变化glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);//绘制三角形glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);}

运行截图如下:
这里写图片描述

最新文章更新在微信公众号上,欢迎关注获取详情:
这里写图片描述

完整代码Github地址这里写链接内容

这篇关于Android Open GL ES - 绘制三角形的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

SpringBoot整合(ES)ElasticSearch7.8实践

《SpringBoot整合(ES)ElasticSearch7.8实践》本文详细介绍了SpringBoot整合ElasticSearch7.8的教程,涵盖依赖添加、客户端初始化、索引创建与获取、批量插... 目录SpringBoot整合ElasticSearch7.8添加依赖初始化创建SpringBoot项

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

使用Python绘制3D堆叠条形图全解析

《使用Python绘制3D堆叠条形图全解析》在数据可视化的工具箱里,3D图表总能带来眼前一亮的效果,本文就来和大家聊聊如何使用Python实现绘制3D堆叠条形图,感兴趣的小伙伴可以了解下... 目录为什么选择 3D 堆叠条形图代码实现:从数据到 3D 世界的搭建核心代码逐行解析细节优化应用场景:3D 堆叠图

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

QT6中绘制UI的两种方法详解与示例代码

《QT6中绘制UI的两种方法详解与示例代码》Qt6提供了两种主要的UI绘制技术:​​QML(QtMeta-ObjectLanguage)​​和​​C++Widgets​​,这两种技术各有优势,适用于不... 目录一、QML 技术详解1.1 QML 简介1.2 QML 的核心概念1.3 QML 示例:简单按钮

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四