OpenGL ES for Android 环境搭建

移动开发 作者: 2024-08-25 13:40:01
在Android上运行OpenGL ES程序需要用到GLSurfaceView控件,GLSurfaceView继承自SurfaceView并实现了GLThread,通过OpenGL ES进行绘制。 O
  • 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规范。
<uses-feature android:glEsVersion="0x00020000" android:required=true" />
<?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=
tools:context=.MainActivity">

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

</androidx.constraintlayout.widget.ConstraintLayout>
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()
}

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

Renderer必须实现GLSurfaceView.Renderer接口,并实现onSurfaceCreated,onDrawFrame,onSurfaceChanged方法,OpenGL ES的渲染工作由此Renderer实现。
MyRenderer的实现:
 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:GLSurfaceView创建完成,也代表OpenGL ES环境创建完成,通常情况下在此方法中创建Program及初始化参数。
  • onSurfaceChanged:当Surface发生变化的时候回调,比如竖屏转横屏导致GLSurfaceView大小发生变化,通常情况下在此方法中设置绘制窗口及和GLSurfaceView大小有关系的参数。
  • onDrawFrame:执行OpenGL ES渲染工作,由系统以一定的频率来调用重绘View,当设置GLSurfaceView的渲染模式为GLSurfaceView.RENDERMODE_CONTINUOUSLY或不设置时,系统就会主动回调onDrawFrame()方法,如果设置为 RENDERMODE_WHEN_DIRTY ,手动调用requestRender(),才会渲染。
  • 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;
}
precision mediump float;
 main()
{
gl_FragColor = vec4(1,0,1)">1);
}
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(检查shader状态
GLES20.glGetShaderiv(shaderHandle,GLES20.GL_COMPILE_STATUS,compileStatus,1)">if (compileStatus[0] == 输入shader异常日志
Log.e(TAG,1)">Error compile shader:${GLES20.glGetShaderInfoLog(shaderHandle)}删除shader
GLES20.glDeleteShader(shaderHandle)
shaderHandle = 
}
}
if (shaderHandle == ) {
Log.e(TAG,Error create shader)
}
return shaderHandle
}
fun createAndLinkProgram(vertexCode: String,fragmentCode: String): Int {
创建一个空的program
var programHandle = GLES20.glCreateProgram()
if (programHandle != 编译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(检测program状态
GLES20.glGetProgramiv(programHandle,GLES20.GL_LINK_STATUS,linkStatus,1)">if (linkStatus[Error link program:${GLES20.glGetProgramInfoLog(programHandle)}删除program
GLES20.glDeleteProgram(programHandle)
programHandle = if (programHandle == Error create program programHandle
}
 fun createProgram() {
var vertexCode =
AssetsUtils.readAssetsTxt(
context = context,filePath = glsl/triangle_vertex.glsl
)
var fragmentCode =glsl/triangle_fragment.glsl
)
mProgramHandle = GLTools.createAndLinkProgram(vertexCode,fragmentCode)
}
val loc = GLES20.glGetAttribLocation(mProgramHandle,1)">vPosition")

顶点坐标轴以屏幕中心为原点(0,0),z轴的正方向为穿透屏幕指向外面。三角形的顶点坐标设置如下:
var vertexBuffer = GLTools.array2Buffer(
floatArrayOf(
0.0f,1)">0.5f, top
- bottom left
0.0f  bottom right
)
)
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( buffer
}

创建OpenGL ES绘制窗口通常是在onSurfaceChanged中设置,
GLES20.glViewport(
绘制在onDrawFrame中执行,
) {
GLES20.glUseProgram(mProgramHandle)
GLTools.setAttributePointer(vPositionLoc,vertexBuffer,1)">3)
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,1)">)
}
  • Location是刚才获取vPosition的句柄
  • buffers 是生成的顶点数据,
  • pointSize 表示每个顶点个数,上面顶点的个数是3个,
fun setAttributePointer(location: Int,buffers: FloatBuffer,pointSize: Int) {
buffers.position()
GLES20.glEnableVertexAttribArray(location)
GLES20.glVertexAttribPointer(location,pointSize,GLES20.GL_FLOAT,false,buffers)
}
  • 第一个参数mode,表示绘制的方式,可选择的值有:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
  • 第二个参数表示从数组缓存中的哪一位开始绘制,一般为0。
  • 第三个参数表示绘制顶点的数量。
原创声明
本站部分文章基于互联网的整理,我们会把真正“有用/优质”的文章整理提供给各位开发者。本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
本文链接:http://www.jiecseo.com/news/show_68422.html