OpenGL ES for Android 环境搭建

在Android上运行OpenGL ES程序需要用到GLSurfaceView控件,GLSurfaceView继承自SurfaceView并实现了GLThread,通过OpenGL ES进行绘制。

  • OpenGL ES1.0是基于OpenGL 1.3的,OpenGL ES1.1是基于OpenGL 1.5的。Android1.0和更高的版本支持这个API规范。OpenGL ES 1.x是针对固定硬件管线的。
  • OpenGL ES2.0是基于OpenGL 2.0的,不兼容OpenGL ES 1.x。Android 2.2(API 8)和更高的版本支持这个API规范。OpenGL ES 2.x是针对可编程硬件管线的。
  • OpenGL ES3.0的技术特性几乎完全来自OpenGL 3.x的,向下兼容OpenGL ES 2.x。Android 4.3(API 18)及更高的版本支持这个API规范。
  • OpenGL ES3.1基本上可以属于OpenGL 4.x的子集,向下兼容OpenGL ES3.0/2.0。Android 5.0(API 21)和更高的版本支持这个API规范。

Android工程中OpenGL ES的版本在AndroidManifest.xml中指定:

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

0x00020000表示支持OpenGL ES 2.0。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<android.opengl.GLSurfaceView
android:id="@+id/glSurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

在Activity中初始化GLSurfaceView

class TriangleActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//设置opengl es版
glSurfaceView.setEGLContextClientVersion(2)
//设置renderer
glSurfaceView.setRenderer(MyRenderer(context = baseContext))
//设置渲染模式
glSurfaceView.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
}

override fun onResume() {
super.onResume()
glSurfaceView.onResume()
}

override fun onPause() {
super.onPause()
glSurfaceView.onPause()
}
}

OpenGL ES版本号和AndroidManifest.xml中版本号保持一致,当然我们也可以在设置版本之前判断当前设备是否支持设置的版本,下面的代码判断是支持ES 2.0版本。

fun supportsEs2(context: Context): Boolean {
val configurationInfo =
(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).deviceConfigurationInfo
return configurationInfo.reqGlEsVersion >= 0x20000
}

setRenderMode方法是设置GLSurfaceView渲染模式,渲染模式有RENDERMODE_WHEN_DIRTY和RENDERMODE_CONTINUOUSLY两种,RENDERMODE_WHEN_DIRTY表示当需要的时候才渲染,只有在调用requestRender或者onResume等方法时才渲染,RENDERMODE_CONTINUOUSLY表示一直渲染。
setRenderMode一定要在setRenderer方法之后调用,另外一般需要在Activity或者Fragment的onPause和onResume生命周期中调用GLSurfaceView的onPause和onResume方法,节省系统资源。

Renderer必须实现GLSurfaceView.Renderer接口,并实现onSurfaceCreated ,onDrawFrame,onSurfaceChanged方法,OpenGL ES的渲染工作由此Renderer实现。
MyRenderer的实现:

class MyRenderer(val context: Context) : GLSurfaceView.Renderer {
override fun onDrawFrame(p0: GL10?) {
}
override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int){
}
override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
}
}

onSurfaceCreated ,onDrawFrame,onSurfaceChanged方法说明如下:

  • onSurfaceCreated:GLSurfaceView创建完成,也代表OpenGL ES环境创建完成,通常情况下在此方法中创建Program及初始化参数。
  • onSurfaceChanged:当Surface发生变化的时候回调,比如竖屏转横屏导致GLSurfaceView大小发生变化,通常情况下在此方法中设置绘制窗口及和GLSurfaceView大小有关系的参数。
  • onDrawFrame:执行OpenGL ES渲染工作,由系统以一定的频率来调用重绘View,当设置GLSurfaceView的渲染模式为GLSurfaceView.RENDERMODE_CONTINUOUSLY或不设置时,系统就会主动回调onDrawFrame()方法, 如果设置为 RENDERMODE_WHEN_DIRTY ,手动调用requestRender(),才会渲染。

在OpenGL ES中Shader和Program是两个非常重要的概念,Program需要Vertex Shader(顶点Shader和Fragment Shader(片段Shader),Renderer的渲染就是在执行Program。

  • Vertex Shader(顶点Shader)处理顶点数据,对于发送给GPU的每一个顶点都要执行一次Vertex Shader,它的作用就是把顶点在虚拟空间中的三维坐标变换为屏幕上的二维坐标,并带有深度信息。
  • Fragment Shader计算每个像素的颜色和其他属性。它通过应用光照值、凹凸贴图,阴影,镜面高光,半透明等处理来计算像素的颜色并输出。


Shader可以以字符串形式存在也可以单独存放在文件中,建议写在assets目录下并以.glsl结尾,因为Android Studio安装GLSL插件可以高亮其代码,便于查找错误。
在assets下创建glsl文件夹,用于存放glsl文件,创建triangle_vertex.glsl文件,保存Vertex Shader代码:

attribute vec4 vPosition;
void main() {
gl_Position = vPosition;
}

创建triangle_fragment.glsl文件,保存Fragment Shader代码:

precision mediump float;
void main()
{
gl_FragColor = vec4(1,0,0,1);
}

上面代码表示顶点区域内绘制为红色,vec4内的值表示r,g,b,a。
将上面2个shader文件编译为Shader,

private fun compileShader(shaderType: Int, shaderSource: String): Int {
//创建一个空shader
var shaderHandle: Int = GLES20.glCreateShader(shaderType)
if (shaderHandle != 0) {
//加载shader源码
GLES20.glShaderSource(shaderHandle, shaderSource)
//编译shader
GLES20.glCompileShader(shaderHandle)
val compileStatus = IntArray(1)
//检查shader状态
GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0)
if (compileStatus[0] == 0) {
//输入shader异常日志
Log.e(TAG, "Error compile shader:${GLES20.glGetShaderInfoLog(shaderHandle)}")
//删除shader
GLES20.glDeleteShader(shaderHandle)
shaderHandle = 0
}
}
if (shaderHandle == 0) {
Log.e(TAG, "Error create shader")
}
return shaderHandle
}

ShaderType分为GLES20.GL_VERTEX_SHADER和GLES20.GL_FRAGMENT_SHADER,GLES20.GL_VERTEX_SHADER编译Vertex Shader的,GLES20.GL_ FRAGMENT _SHADER编译Fragment Shader。
将Shader链接到program,

fun createAndLinkProgram(vertexCode: String, fragmentCode: String): Int {
//创建一个空的program
var programHandle = GLES20.glCreateProgram()
if (programHandle != 0) {
//编译shader
val vertexShaderHandle = compileShader(GLES20.GL_VERTEX_SHADER, vertexCode)
val fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentCode)
//绑定shader和program
GLES20.glAttachShader(programHandle, vertexShaderHandle)
GLES20.glAttachShader(programHandle, fragmentShaderHandle)
//链接program
GLES20.glLinkProgram(programHandle)

val linkStatus = IntArray(1)
//检测program状态
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0)
if (linkStatus[0] == 0) {
Log.e(TAG, "Error link program:${GLES20.glGetProgramInfoLog(programHandle)}")
//删除program
GLES20.glDeleteProgram(programHandle)
programHandle = 0
}
}
if (programHandle == 0) {
Log.e(TAG, "Error create program")
}
return programHandle
}

最终返回program的句柄,这2步是固定的,因为我们将其封装为工具类GLTools,供以后使用。
使用工具类GLTools创建program:

private fun createProgram() {
var vertexCode =
AssetsUtils.readAssetsTxt(
context = context,
filePath = "glsl/triangle_vertex.glsl"
)
var fragmentCode =
AssetsUtils.readAssetsTxt(
context = context,
filePath = "glsl/triangle_fragment.glsl"
)
mProgramHandle = GLTools.createAndLinkProgram(vertexCode, fragmentCode)
}

program的创建放在Renderer的onSurfaceCreated方法中,创建成功后,获取Shader中参数句柄及设置顶点数据。获取Vertex Shader中vPosition句柄:

val loc = GLES20.glGetAttribLocation(mProgramHandle, "vPosition")

顶点数据需要了解顶点坐标系统,如下图:

顶点坐标轴以屏幕中心为原点(0,0),z轴的正方向为穿透屏幕指向外面。三角形的顶点坐标设置如下:

var vertexBuffer = GLTools.array2Buffer(
floatArrayOf(
0.0f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
)
)

工具类GLTools中array2Buffer是将顶点数据转换为FloatBuffer,array2Buffer方法定义如下:

fun array2Buffer(array: FloatArray): FloatBuffer {
val bb = ByteBuffer.allocateDirect(array.size * 4)
bb.order(ByteOrder.nativeOrder())
var buffer = bb.asFloatBuffer()
buffer.put(array)
buffer.position(0)
return buffer
}


创建OpenGL ES绘制窗口通常是在onSurfaceChanged中设置,

GLES20.glViewport(0, 0, width, height)
  • 第一个参数(x):表示窗口x坐标,屏幕左上角为原点
  • 第二个参数(y):表示窗口y坐标,(0,0)表示屏幕左上角
  • 第三个参数(width):表示窗口的宽
  • 第四个参数(height):表示窗口的高


绘制在onDrawFrame中执行,

override fun onDrawFrame(p0: GL10?) {
GLES20.glUseProgram(mProgramHandle)
GLTools.setAttributePointer(vPositionLoc, vertexBuffer, 3)
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3)
}

GLES20.glUseProgram(mProgramHandle)表示启动当前program,mProgramHandle是上面创建Program返回的句柄。

GLTools.setAttributePointer(vPositionLoc, vertexBuffer, 3)表示将顶点数据设置给program,参数说明情况如下:

  • Location是刚才获取vPosition的句柄
  • buffers 是生成的顶点数据,
  • pointSize 表示每个顶点个数,上面顶点的个数是3个,

setAttributePointer为封装的工具类方法:

fun setAttributePointer(location: Int, buffers: FloatBuffer, pointSize: Int) {
buffers.position(0)
GLES20.glEnableVertexAttribArray(location)
GLES20.glVertexAttribPointer(location, pointSize, GLES20.GL_FLOAT, false, 0, buffers)
}

glDrawArrays方法是绘制,参数说明情况如下:

  • 第一个参数mode,表示绘制的方式,可选择的值有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
  • 第二个参数表示从数组缓存中的哪一位开始绘制,一般为0。
  • 第三个参数表示绘制顶点的数量。

往期回顾

OpenGL ES for Android 总览

 

如果此文章对您有所帮助,欢迎扫码关注订阅号。

原文地址:https://www.cnblogs.com/mengqd/p/12215620.html

时间: 2024-08-02 13:03:23

OpenGL ES for Android 环境搭建的相关文章

android环境搭建遇到的问题

1.出现This AndroidSDK requires  Android Developer Toolkit version 20.0.0or above 的报错  windows 下面安装Android虚拟机,有时候选择更新SDK后,在Eclipse preference里指向android_sdk_windows_x86时.会出现诸如This AndroidSDK requires  Android Developer Toolkit version 20.0.0or above这样的提示

Android环境搭建的步骤

Android 环境搭建步骤 这里简单介绍一下学习Android之后如何搭建环境的问题 一.    在搭建环境之前,首先你要先下载Java JDK(根据系统位数选择下载是64位或32位的),Eclipse,Android,ADT插件,然后把JavaJDK的系统环境搭建好(这些下载地址网上有,可以自己去找). 二.    在系统上配置JavaJDK的系统变量 首先我们需要设置JDK的两个系统变量,分别为JAVA_HOME,Path两个.(这个两个变量怎么设置,网上也有,在这就不再赘述) 三.   

Cocos2d-x 3.1.1 学习日志11--一Windows下Android环境搭建(一定对你有用的!!)

安装步骤::(多么痛的领悟!!) 1. 配置JDK JDK下载地址: 设置环境变量: JAVA_HOME=C:\Program Files (x86)\Java\jdk1.7.0_21 CLASSPATH=.;%JAVA_HOME%\lib; Path增加%JAVA_HOME%\bin; 设置完后打开cmd,输入java -version 如果出现下面提示,表明环境变量设置成功: C:\Users\arlin>java -version java version "1.7.0_21&quo

Android # Android 环境搭建之 Python 配置

在终端输入python,然后import sysprint sys.path The Python Tutorial - Python v2.7.7 documentation https://docs.python.org/2.7/tutorial/index.html Python 3.1.2和2.7比较哪个版本更稳定?_python吧_百度贴吧 http://tieba.baidu.com/p/936048566 python2.7.3和3.3.2的区别_百度知道 http://zhida

cocos2d-x Android 环境搭建问题汇总

初次接触Cocos2d-x,准备搭建一个hello world的Android环境,问题遇到很多.在此记录,为自己,也为大家,避免重走弯路! 具体的环境搭建,可以参考官方的文档.在Windows7平台搭建Cocos2d-x Android开发环境. 1.Android-ndk-r10不能放在具有空格的路径下. 2.进入工程目录下的proj.android目录,执行build_native.py,编译出错: jni/../../cocos2d/cocos/./3d/CCBundleReader.c

Xcode环境下OpenGL C++ GLFW开发环境搭建

操作系统版本:MacOS Mavericks 10.9.2 Xcode版本:5.0.1 OpenGL版本:4.10 GLFW版本:3.0.4 一.GLFW编译 1.下载并安装cmake(当前最新版本为2.8.12.2) http://www.cmake.org/cmake/resources/software.html 下载cmake-2.8.12.2-Darwin64-universal.dmg文件安装即可 2.下载GLFW源代码(当前最新版本为3.0.4) http://www.glfw.o

cocos2d-x 3.0 Android环境搭建(亲測通过)

网上一大堆讲述coco2d-x 3.0 版本号的android环境搭建.真是不忍直視.讲的不清不楚,真是不知道他们自己有没有測试过.今天正好忙完项目有点时间去部署了下android环境. cocos2d-x 3.0 版本号大大简化了android环境的部署,简单到仅仅需一条命令就能够了.好了废话不多说開始进入正题.(我用的引擎是cocos2d-x 3.0 正式版,測试项目是创建的lua项目. 系统为mac) 首先主要的andriod  sdk.ndk自己參照网上配置下.新版3.0须要多配置一下a

cocos2d-x_ Windows下Android环境搭建

在Windows环境下编译cocos2d-x-3.0 Android-NDK编译:cocos2d-x(二) Mac 下搭建:http://www.cocoachina.com/bbs/read.php?tid=199238 1. 安装配置开发环境 安装JDK  jdk-8u5-windows-i586 安装ant  apache-ant-1.9.4-bin.zip 安装SDK  adt-bundle-windows-x86-20140321 安装NDK  android-ndk-r9d-wind

Android 环境搭建 版本问题

jdk1.6 1.7  eclipse 3.7.2    SDK-r12 ADT 12 SDK和ADT必须配套 搭建环境需要四个软件: 1.JDK(这是最新版本jdk1.7官方下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html) 2.SDK(这是最新版本android-sdk_r12官方下载地址:http://developer.android.com/sdk/index.html) 3.Eclipse(