android studio上第一個opengl es程式
android上opengl es基礎知識
Google在Android2.2 以後支援 opengl es 2.2,在Android 4.3以後引入opengl es 3.0。Android中使用openGL會用到GLSurfaceView控制元件, GLSurfaceView.Renderer,在Android studio的debug模式下我們可以清楚的看到Renderer的各個回撥函式發生在非UI主執行緒,即渲染執行緒,具體渲染是在一塊稱為”surface”(在openGL裡面稱為ViewPort視口)的地方完成,渲染繪製完成後在將渲染結果直接在主執行緒顯示,實際上GLSurfaceView在View Hierarchy上”穿洞”,讓底層open gl surface顯示出來。同時,需要考慮GLSurfaceView和Activity的各個生命週期的問題。
另一方面,在Android 4.0以後提供了一個紋理檢視(TextureView)可以也可以渲染opengl,TextureView像普通view一樣不在需要”穿洞”了,但是TextureView沒有內建opengl的初始化操作。
第一個opengl es程式
如下程式碼是在Android studio上建立的第一個opengl es專案:
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
private boolean rendererSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
// Check if the system supports OpenGL ES 2.0.
final ActivityManager activityManager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo =
activityManager.getDeviceConfigurationInfo();
/*
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
*/
// 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")));
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:
*
* <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;
}
setContentView(glSurfaceView);
}
@Override
protected void onPause() {
super.onPause();
if (rendererSet) {
glSurfaceView.onPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (rendererSet) {
glSurfaceView.onResume();
}
}
}
supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;是用來判斷是否支援opengl es2.0,同時在模擬器的話可能支援不是多好,所以程式碼進行了判斷。 glSurfaceView.setEGLContextClientVersion(2);是來具體設定opengl版本,配置surface檢視。同時需要注意Activity的生命週期需要回調glSurfaceView對應的生命週期,這樣surface檢視才能正確處理渲染執行緒暫停和繼續,同時釋放和續用opengl的上下文。
下面是FirstOpenGLProjectRenderer 的程式碼:
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);
}
}
主要有三個回撥方法,onSurfaceCreated,onSurfaceChanged,onDrawFrame。之前已經說過了,這些方法回調發生在渲染執行緒。onSurfaceCreated是在surface被建立時,GLSurfaceView會回撥這個方法。onSurfaceChanged是在surface被建立後每次在surface尺寸發生變化的時候GLSurfaceView會回撥,比如橫豎屏切換會回撥這個方法。onDrawFrame是當每繪製一幀就會被GLSurfaceView回撥,通常一定要在這個方法裡做點事情哪怕是設定清屏顏色,因為這個方法呼叫之後會把渲染結果surface給螢幕顯示,不能說什麼都沒有,這樣的話可能會顯示花屏。另外,通常GLSurfaceView會以顯示屏的的重新整理頻率來回調onDrawFrame進行渲染,當然我們可以設定GLSurfaceView的渲染模式來修改,呼叫
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
//GLSurfaceView.RENDERMODE_CONTINUOUSLY:持續渲染(預設)
//GLSurfaceView.RENDERMODE_WHEN_DIRTY:髒渲染,命令渲染;即有兩種渲染模式髒渲染和持續渲染(預設)。使用髒渲染需要和glSurfaceView.requestRender配合使用。
綜上分析,在onSurfaceCreated裡需要設定清屏色,本文為紅色 glClearColor(1.0f, 0.0f, 0.0f, 0.0f);在onSurfaceChanged裡設定視口viewport大小即通知opengl需要渲染視口大小即surface大小。注意:視口viewport是opengl裡面的概念,surface是GLSurfaceView裡提供給底層渲染顯示的區域,故可以理解為同一個。在onDrawFrame裡面 glClear(GL_COLOR_BUFFER_BIT);是清楚所有顏色緩衝器,這樣就會顯示清屏色即 glClearColor(1.0f, 0.0f, 0.0f, 0.0f)設定的紅色。
到此,本文章結束。主要講解基礎概念,基礎原理。本文程式碼地址:
https://github.com/pangrui201/OpenGlesProject/tree/master/OpenGlesProject_lesson1