什么是OpenGL?
OpenGL的全称是Open Graphics Library,简单说就是图形库。
什么是OpenGL ES?
OpenGL ES的全称是OpenGL for Embedded Systems,它是 OpenGL 三维图形 API 的子集,是针对手机等嵌入式设备而设计。
在OpenGL ES的世界里,没有四边形、多边形,无论多复杂的图形都是由点、线和三角形组成的
一、初始化OpenGL
我们需要一个特殊的类GLSurfaceView来初始化OpenGL,GLSurfaceView会处理OpenGL初始化过程中比较基本的操作,例如配置显示设备(display)以及在后台线程中渲染,渲染是指在显示设备中一个叫做surface的区域完成的,这个区域有时候也称为(viewpoint)。
在幕后,GLSurfaceView实际上为它自己创建了一个窗口(window),并在视图层次(view hierarchy)上穿了一个“洞”,让底层的OpenGL surface能够显示出来,对应大多数情况这就够了,但是GLSurfaceView与常规的View不同,它没有动画和变形特效,因为GLSurfaceView是窗口(window)的一部分。
从Android4.0开始,Android提供了一个纹理视图(TextrueView),它也可以渲染OpenGL而不用创建单独的窗口或者打洞,意味着可以向常规视图一样可以被操作并且支持动画和变形处理,当时TextureView内部没有处理OpenGL的初始化,需要自定义OpenGL的初始化并在TextureView上运行,或者将GLSurfaceView的源码拷贝出来在TextureView上做适配。
二、创建GLSurfaceView的实例
package com.example.openglstudy.demo1
import android.app.ActivityManager
import android.content.Context
import android.opengl.GLSurfaceView
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.openglstudy.R
class FirstOpenGLProjectActivity : AppCompatActivity() {
private val glSurfaceView: GLSurfaceView by lazy {
GLSurfaceView(this) //创建GLSurfaceView
}
private var rendererSet = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first_open_glproject)
//1.检查系统是否支持OpenGL ES 2.0
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val supportsEs2 =
activityManager.deviceConfigurationInfo.reqGlEsVersion >= 0x20000 //模拟器上不支持,所以还要以下的判断条件了
|| (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
&& (Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")));
if (supportsEs2) {
//2.配置渲染的表面rendering surface
glSurfaceView.setEGLContextClientVersion(2) //Request an OpenGL ES 2.0 compatible context
//3.设置自定义的render渲染器
glSurfaceView.setRenderer(FirstOpenGLProjectRenderer())
rendererSet = true
} else {
/*
* This is where you could create an OpenGL ES 1.x compatible
* renderer if you wanted to support both ES 1 and ES 2. Since we're
* not doing anything, the app will crash if the device doesn't
* support OpenGL ES 2.0. If we publish on the market, we should
* also add the following to AndroidManifest.xml:
*
* <uses-feature android:glEsVersion="0x00020000"
* android:required="true" />
*
* This hides our app from those devices which don't support OpenGL
* ES 2.0.
*/
Toast.makeText(this, "This device does not support OpenGL ES 2.0.", Toast.LENGTH_LONG)
.show()
return
}
//最后展示glSurfaceView
setContentView(glSurfaceView)
}
override fun onPause() {
super.onPause()
if (rendererSet) {
glSurfaceView.onPause()
}
}
override fun onResume() {
super.onResume()
if (rendererSet) {
glSurfaceView.onResume()
}
}
}
三、创建Render类
GLSurfaceView会在一个单独的线程中调用渲染器的方法,默认情况下,GLSurfaceView会以显示设备的刷新频率不断地渲染,
当然,它也可以配置为按请求渲染,只需要用GLSurfaceView.RENDERMODE_WHEN_DIRTY作为参数调用GLSurfaceView.setRenderMode()即可。
自定义类继承至GLSurfaceView.Renderer
package com.example.openglstudy.demo1
import android.opengl.GLES20.*
import android.opengl.GLSurfaceView
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
class FirstOpenGLProjectRenderer : GLSurfaceView.Renderer{
/**
* 当Surface被创建的时候,GLSurfaceView会调用这个方法,这发生在应用程序第一次运行的时候,并且当设备被唤醒
* 或者用户从其他activity切换回来时,这个方法也可能会被调用,意味着这个方法会调用多次
*/
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
//调用该方法来设置清屏用的颜色,红色分量设置为1,那么当屏幕被清空时就会显示红色,色彩的取值范围是[0,1]
glClearColor(1.0f,0.0f,0.0f,0.0f)
}
/**
* 在Surface被创建以后,每次Surface尺寸发生变化时,都会被GLSurfaceView调用.
* 在横竖屏切换的时候,Surface尺寸会发生变化
*/
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
//设置视口尺寸来告诉OpenGL可以用来渲染的surface的大小
glViewport(0,0,width,height)
}
/**
* 当绘制一帧时,这个方法会被GLSurfaceView调用,在这个方法中,我们一定要绘制一些东西,即使只是清空屏幕;
* 因为,在这个方法返回后,渲染缓冲区会被交换并显示在屏幕上,如果什么都没有画,可能会看到闪烁效果
*/
override fun onDrawFrame(gl: GL10?) {
//调用下面方法清空屏幕,这会清除屏幕上的所有颜色,并调用之前glClearColor定义的颜色来填充整个屏幕
glClear(GL_COLOR_BUFFER_BIT)
}
}
上面3个接口的方法参数中都有一个GL10,它是OpenGL ES 1.0的API遗留下来的,如果要编写OpenGL ES 1.0的渲染器,就要用到
这个参数,但是对于OpenGL ES 2.0, GLES20类提供了静态方法来存取。
ok,到目前为止就可以运行起来看看效果了,效果就如下图所示全屏的红色,这是因为我们设置的清屏颜色是红色。