第一個(gè)OpenGL程序
初始化 OpenGL
使用GLSurfaceView初始化OpenGL,GLSurfaceView會(huì)處理OpenGL初始化過(guò)程中比較基本的操作窟扑,如配置顯示設(shè)備(display)以及在后臺(tái)線(xiàn)程中渲染真仲,渲染是在顯示設(shè)備中一個(gè)稱(chēng)為“surface”的特定區(qū)域完成的袋马,有時(shí)也稱(chēng)為視口(viewport),在 Activity 被暫停的時(shí)候秸应,需要釋放OpenGL的資源虑凛,GLSurfaceView為此提供了很多輔助方法
創(chuàng)建 GLSurfaceView
public class MainActivity extends AppCompatActivity {
// 處理OpenGL初始化過(guò)程,如配置顯示設(shè)備(display)以及在后臺(tái)線(xiàn)程中渲染
private GLSurfaceView glSurfaceView;
// 記錄GLSurfaceView是否處于有效狀態(tài)
private boolean rendererSet = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 創(chuàng)建GLSurfaceView
glSurfaceView = new GLSurfaceView(this);
// 把GLSurfaceView加入到這個(gè)activity中软啼,并把它顯示到屏幕上
setContentView(glSurfaceView);
// 檢查是否支持 OpenGLES 2
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
boolean supportEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportEs2) {
// 設(shè)置版本
glSurfaceView.setEGLContextClientVersion(2);
// 配置渲染器桑谍,當(dāng)surface創(chuàng)建或者發(fā)生變化,以及要繪制一幅新幀時(shí)祸挪,渲染器都會(huì)被GLSurfaceView調(diào)用
glSurfaceView.setRenderer(new com.test.opengl.draw1.MyRenderer(this));
// 表示渲染器已經(jīng)配置過(guò)了锣披,glSurfaceView處于有效狀態(tài)
rendererSet = true;
}
}
@Override
protected void onResume() {
super.onResume();
if (rendererSet) {
// 繼續(xù)后臺(tái)渲染線(xiàn)程,續(xù)用OpenGL上下文
glSurfaceView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (rendererSet) {
// 暫停后臺(tái)渲染線(xiàn)程贿条,釋放OpenGL上下文
glSurfaceView.onPause();
}
}
}
GLSurfaceView實(shí)際上為它自己創(chuàng)建了一個(gè)窗口(window)雹仿,并在視圖層次(View Hierarchy)上穿了個(gè)“洞”,讓底層的OpenGL surface顯示出來(lái)。GLSurfaceview與常規(guī)視圖(view)不同整以,它沒(méi)有動(dòng)畫(huà)或者變形特效胧辽,因?yàn)镚LSurfaceView是窗口( window)的一部分
TextureView 可以渲染OpenGL而不用創(chuàng)建單獨(dú)的窗口,可以被操作公黑,且有動(dòng)畫(huà)和變形特效邑商。但TextureView類(lèi)沒(méi)有內(nèi)置OpenGL初始化操作,要想使用 TextureView凡蚜,需要執(zhí)行自定義的OpenGL初始化人断,并在TextureView上運(yùn)行
按需渲染
GLSurfaceView會(huì)在一個(gè)單獨(dú)的線(xiàn)程中調(diào)用渲染器的方法。默認(rèn)情況下朝蜘, GLSurfaceView會(huì)以顯示設(shè)備的刷新頻率不斷地渲染恶迈,也可以用下面的方法配置為按請(qǐng)求渲染
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
渲染線(xiàn)程與主線(xiàn)程通信
因?yàn)?Android 的 GLSurfaceView在后臺(tái)線(xiàn)程中執(zhí)行渲染,因此只能在這個(gè)渲染線(xiàn)程中調(diào)用OpenGL的方法芹务,與主線(xiàn)程之間的通信可以用如下方法:
- 在主線(xiàn)程中的GLSurfaceView實(shí)例可以調(diào)用queueEvent()方法傳遞一個(gè)Runnable給后臺(tái)渲染線(xiàn)程執(zhí)行
- 渲染線(xiàn)程可以調(diào)用Activity的runOnUiThread()方法傳遞一個(gè)Runnable給主線(xiàn)程執(zhí)行
創(chuàng)建渲染器 Renderer
public class MyRenderer implements GLSurfaceView.Renderer {
/**
* 當(dāng)Surface被創(chuàng)建的時(shí)候蝉绷,GLSurfaceView會(huì)調(diào)用這個(gè)方法
* 程序第一次運(yùn)行鸭廷、設(shè)備被喚醒或者從其他activity切換回來(lái)時(shí),可能會(huì)被調(diào)用熔吗,因此可能會(huì)被調(diào)用多次
*
* @param gl10
* @param eglConfig
*/
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
// 設(shè)置清空屏幕用的顏色
glClearColor(1f, 0f, 0f, 1f);
}
/**
* Surface被創(chuàng)建以后辆床,每次Surface尺寸變化時(shí),這個(gè)方法都會(huì)被GLSurfaceView調(diào)用
* 例如在橫屏桅狠、豎屏來(lái)回切換的時(shí)候讼载,Surface尺寸會(huì)發(fā)生變化
*
* @param gl10
* @param width
* @param height
*/
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
// 設(shè)置視口(viewport)尺寸,告訴OpenGL可以用來(lái)渲染的surface的大小
glViewport(0, 0, width, height);
}
/**
* 當(dāng)繪制一幀時(shí)中跌,這個(gè)方法會(huì)被GLSurfaceView調(diào)用咨堤,在這個(gè)方法中,一定要繪制一些東西漩符,即使只是清空屏幕
* 因?yàn)橐淮谶@個(gè)方法返回后,渲染緩沖區(qū)會(huì)被交換并顯示在屏幕上嗜暴,如果什么都沒(méi)畫(huà)凸克,可能會(huì)看到閃爍效果
*
* @param gl10
*/
@Override
public void onDrawFrame(GL10 gl10) {
// 清空屏幕,會(huì)擦除屏幕上的所有顏色闷沥,并用之前glClearColor()調(diào)用定義的顏色填充整個(gè)屏幕
glClear(GL_COLOR_BUFFER_BIT);
}
}
清空屏幕
清空屏幕是因?yàn)槲剑钚碌腉PU使用特殊的渲染技術(shù),如果屏幕是干凈的舆逃,GPU他們能工作得更快蚂维,通過(guò)讓 GPU清空屏幕,可以節(jié)省幀拷貝浪費(fèi)的時(shí)間