一.基本概念
OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
OpenGL ES在Android上的应用领域广泛,主要用于游戏开发,音视频开发(如滤镜),在�VR,AR领域也有应用(如VR照相机)
Android本身支持了OpenGL,官方文档在此,官方文档用的例子是基于OpenGL ES2.0的,2.0与1.0的区别在于1.0采用固定管线来编程,而2.0则采用着色器来编程,增强了开发者的灵活性,由于现在大部分设备都支持2.0以上的OpenGL ES的驱动,所以这里我们就以2.0为例,至于2.0以上的版本,原理是一致的,api也相差不大。
二.初始化OpenGL
1.首先我们新建一个新的Android项目,命名为“FirstOpenGLApplication”
Android中的GLSurfaceView封装了OpenGL在设备上的显示逻辑,负责处理OpenGL初始化过程中比较基本的操作,如配置显示设备以及在后台线程中渲染,渲染是在显示设备中一个称为"surface"的特定区域完成的, 有时也称为视口(viewport)
2.然后我们检查设备是否支持OpenGL ES2.0
public class FirstOpenGLActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
final ActivityManager activityManager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
}
}
如果你的设备是模拟器的话,需要用以下代码检查
public class FirstOpenGLActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
final ActivityManager activityManager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
// Even though the latest emulator supports OpenGL ES 2.0,
// it has a bug where it doesn't set the reqGlEsVersion so
// the above check doesn't work. The below will detect if the
// app is running on an emulator, and assume that it supports
// OpenGL ES 2.0.
final boolean supportsEs2 =
configurationInfo.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")));
}
}
这段代码测试当前设备是不是模拟器,如果是,就假定它支持2.0,要确保程序能运行,模拟器一定要配置OpenGL ES2.0
3.为OpenGL配置渲染器
if (supportsEs2) {
// Request an OpenGL ES 2.0 compatible context.
glSurfaceView.setEGLContextClientVersion(2);
// Assign our renderer.
glSurfaceView.setRenderer(new 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:
*
*
*
* 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;
}
setContentView(glSurfaceView);
接着新建一个类继承Renderer
public class FirstOpenGLProjectRenderer implements Renderer {
@Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
// Set the background clear color to red. The first component is
// red, the second is green, the third is blue, and the last
// component is alpha, which we don't use in this lesson.
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
/**
* onSurfaceChanged is called whenever the surface has changed. This is
* called at least once when the surface is initialized. Keep in mind that
* Android normally restarts an Activity on rotation, and in that case, the
* renderer will be destroyed and a new one created.
*
* @param width
* The new width, in pixels.
* @param height
* The new height, in pixels.
*/
@Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
// Set the OpenGL viewport to fill the entire surface.
glViewport(0, 0, width, height);
}
/**
* OnDrawFrame is called whenever a new frame needs to be drawn. Normally,
* this is done at the refresh rate of the screen.
*/
@Override
public void onDrawFrame(GL10 glUnused) {
// Clear the rendering surface.
glClear(GL_COLOR_BUFFER_BIT);
}
}
我们来看一下渲染器(Render)的方法
onSurfaceCreated(GL10 glUnused, EGLConfig)
当Suface被创建的时候,GLSurfaceView会调用这个方法,这一般发生在应用程序第一次运行的时候,但是如果你的Activity或者应用进程被回收(可以用开发者选项--不保留活动来模拟),再次回到应用的时候,也会被调用.
onSurfaceChanged(GL10 glUnused, int width, int height)
在Surface被创建后,每次Surface尺寸变化时,这个方法都会被GLSurfaceView调用到。在横屏,竖屏切换的时候,Surface尺寸会发生变化
onDrawFrame(GL10 glUnused)
当绘制一帧时,这个方法会被GLSurfaceView调用。在这个方法中,我们一定要绘制一些东西,即使只是清空屏幕,因为在这个方法返回后,渲染缓冲区会被交换并显示在屏幕上,如果什么都没画,可能会有闪烁的效果。
所以在这里,我们设置清空屏幕的颜色为红色,设置视口(viewport)的大小为GLSurfaceView的大小,并且在每一帧到来时,用glClearColor()设置的红色清屏
三.查看效果
经过了这三个步骤,我们运行一下程序,可以看到屏幕GLSurfaceView的部分被红色沾满,这样我们就完成了OpenGL绘制的第一步啦~
PS: 如果你使用的是模拟器,且程序不工作,并且模拟器的配置选项“Use Host GPU”已经被勾选了,那请试试在glSurfaceView.setRenderer()调用之前加入glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)的调用