寫幾篇文章記錄一下我學習OpenGL的過程,這是第一篇。本片文章通過實現一個清屏操作,先了解一些基本知識。
1.創建一個activity,作為展示頁面:
/**
* 視圖展示頁面,只實現了清屏的操作<br/>
* 1.創建GLSurfaceView<br/>
* 2.調用GLSurfaceView的setRenderer方法,設置Renderer<br/>
* 3.實現Renderer<br/>
* 4.處理Activity的生命周期事件<br/>
*/
public class FirstOpenGLActivity extends AppCompatActivity {
private static final String TAG = FirstOpenGLActivity.class.getSimpleName();
private GLSurfaceView mGLSurfaceView;
/**
* is render seted
*/
private boolean isRendererSet = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
//檢察系統是否支持OpenGL ES 2.0
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
boolean isSupportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
Log.d(TAG, "isSupportsEs2 =" + isSupportsEs2);
if (isSupportsEs2) {
//Request an OpenGL ES 2.0 compatible context
mGLSurfaceView.setEGLContextClientVersion(2);
//Assign our renderer
//當surface創建或者發生變化的時候,以及要繪制一副新幀時,渲染器都會被GLSurfaceView調用
mGLSurfaceView.setRenderer(new FirstOpenGLRenderer());
isRendererSet = true;
} else {
Toast.makeText(this, "this device dose not support OpenGL ES 2.0", Toast.LENGTH_SHORT);
}
setContentView(mGLSurfaceView);
}
//頁面恢復,繼續后台渲染線程,續用OpenGL上下文
@Override
protected void onResume() {
super.onResume();
if (isRendererSet) {
mGLSurfaceView.onResume();
}
}
//頁面不可見,暫停后台渲染線程,釋放OpenGL上下文
@Override
protected void onPause() {
super.onPause();
if (isRendererSet) {
mGLSurfaceView.onPause();
}
}
}
2.創建一個渲染器類實現Renderer接口:
/**
* 渲染器類 實現了Renderer接口
* Created by hsji on 16/1/10.
*/
public class FirstOpenGLRenderer implements GLSurfaceView.Renderer {
/**
* 當surface被創建的時候,GLSurfaceView會調用這個方法;
* 這發生在應用程序第一次運行的時候,並且,當設備被喚醒或者用戶從其他activity切換回來的時,這個方法也可能會被調用。
* 在實踐中,這意味着當程序運行時這個方法可能會被調用多次。
*
* @param gl10
* @param eglConfig
*/
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//設置清空屏幕所使用的顏色RGBA
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}
/**
* 在surface被創建之后,每次surface尺寸發生變化時,這個方法都會被GLSurfaceView調用到。
* 在橫屏、豎屏之間來回切換的時候,Surface的尺寸會發生變化。
*
* @param gl10
* @param width
* @param height
*/
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
//set the OpenGL viewport to to fill the entire surface
GLES20.glViewport(0, 0, width, height);
}
/**
* 當繪制一幀時,這個方法會被GLSurfaceView調用。
* 在這個方法中我們一定要繪制一些東西,即使只是清空屏幕;
* 因為,在這個方法返回之后,渲染緩沖區會被交換並顯示在屏幕上,
* 如果什么都沒畫,可能會看到閃爍效果
*
* @param gl10
*/
@Override
public void onDrawFrame(GL10 gl10) {
//clear the rendering surface
//清空屏幕,擦出屏幕上的所有顏色,並調用之前glClearColor()定義的顏色填充整個屏幕
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
}
一點解釋:怎么會有一個未被使用的參數類型GL10呢?
* 他是OpenGL ES 1.0的API遺留下來的;
* 如果要編寫使用OpenGL ES 1.0的渲染器,就要使用這個參數,
* 但是對於OpenGL ES 2.0,GLES20類提供了靜態方法來存取。
3.渲染線程和主線程之間的交互(之后還會詳細涉及,這里只是一個概要)
GLSurfaceView會在一個單獨的線程中調用渲染器的方法。默認情況下,GLSurfaceView會以顯示設備的刷新頻率不斷的渲染,當然,它也可以配置為按請求渲染,只需要用GLSurfaceView.RENDERMODE_WHEN_DIRTY作為參數調用GLSurfaceView.setRenderMode()即可。
既然android的GLSurfaceView在后台縣城中執行渲染,就必須要小心,只能在這個渲染線程中調用OpenGL,在android主線程中使用UI相關的調用;兩個線程之間的通信可以使用如下方法:在主線程中的GLSurfaceView實例可以調用queueEvent()方法傳遞一個Runnable給后台渲染線程,渲染線程就可以調用Activity的runOnUIThread()來傳遞事件(event)給主線程。
4.運行程序即可看到一個純紅色的屏幕。
