寫幾篇文章記錄一下我學習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.運行程序即可看到一個純紅色的屏幕。