本文目錄
一. OpenGL ES是什么?
二. OpenGL ES的版本
三. EGL是什么?
四. 需要知道的兩個(gè)方法
五. 在Android中使用OpenGL ES的步驟
六. 例子1:簡(jiǎn)單的程序+修改背景顏色
OpenGL ES是什么?
- OpenGL(Open Graphics Library): 是用于渲染2D、3D矢量圖形的跨語(yǔ)言、跨平臺(tái)的應(yīng)用程序編程接口(API),使簡(jiǎn)單的圖形構(gòu)建出復(fù)雜的三維景象。
- OpenGL ES(OpenGl for Embedded System):是 OpenGL三維圖形 API 的子集,針對(duì)手機(jī)、PDA和游戲主機(jī)等嵌入式設(shè)備而設(shè)計(jì),簡(jiǎn)單來(lái)說(shuō)就是OpenGL在移動(dòng)端的閹割版。

OpenGL ES 的版本
| OpenGL ES版本 | Android版本 | 描述 |
|---|---|---|
| OpenGL ES1.0 | Android 1.0+ | OpenGL ES 1.x是針對(duì)固定硬件管線(Fixed Pipeline)的,通過(guò)它內(nèi)建的functions來(lái)設(shè)置諸如燈光、vertexes(圖形的頂點(diǎn)數(shù))、顏色和camera。 |
| OpenGL ES2.0 | Android 2.2(API 8)+ | OpenGL ES 2.x是針對(duì)可編程硬件管線(Programmable Pipeline)的,不兼容OpenGL ES 1.x,需要自己動(dòng)手編寫任何功能。2.0相比于1.0更具靈活性,功能也更強(qiáng)大??梢宰远x頂點(diǎn)和像素計(jì)算,可以讓表現(xiàn)方式更加準(zhǔn)確。 |
| OpenGL ES3.0 | Android 4.3(API 18)+ | 向下兼容OpenGL ES 2.x,是OpenGL ES2.0的擴(kuò)展,支持許多新的渲染技術(shù)、優(yōu)化和顯示質(zhì)量改進(jìn),包括引入了紋理相關(guān)的新功能,對(duì)著色語(yǔ)言進(jìn)行了重大更新和支持著色器新功能的API特性,引入了與幾何形狀規(guī)范和圖元渲染控制相關(guān)的新功能,引入了新的緩沖區(qū)對(duì)象,增添了許多與屏幕外渲染到幀緩沖區(qū)對(duì)象相關(guān)的新功能。 |
| OpenGL ES3.x | Android 5.0 (API 21)+ | 向下兼容OpenGL ES3.0/2.0,Android 5.0(API 21)和更高的版本支持這個(gè)API規(guī)范。 |
EGL是什么?
- EGL (Embedded Graphics Library):EGL 是連接 OpenGL ES 和本地窗口系統(tǒng)的接口,由于OpenGL ES是跨平臺(tái)的,引入EGL就是為了屏蔽不同平臺(tái)上的區(qū)別。
另外,EGL定義了控制 Displays、Contexts 以及 Surfaces 的統(tǒng)一的平臺(tái)接口,但一般情況在 Android 平臺(tái)上開(kāi)發(fā) OpenGL ES 應(yīng)用,無(wú)需直接使用javax.microedition.khronos.egl 包中的類按照EGL步驟來(lái)使用OpenGL ES繪制圖形,因?yàn)樵贏ndroid平臺(tái)中提供了一個(gè)android.opengl 包,GLSurfaceView類提供了對(duì)Display、Surface 和 Context 的管理,大大簡(jiǎn)化了 OpenGL ES 的程序框架,對(duì)應(yīng)大部分 OpenGL ES開(kāi)發(fā),只需調(diào)用一個(gè)方法來(lái)設(shè)置 OpenGLView 需要的GLSurfaceView.Renderer 即可。

EGL提供如下機(jī)制:
- 與設(shè)備的原生窗口系統(tǒng)通信
- 查詢繪圖表面的可用類型和配置
- 創(chuàng)建繪圖表面
- 在OpenGL ES 和其他圖形渲染API之間同步渲染
- 管理紋理貼圖等渲染資源
- 為了讓OpenGL ES能夠繪制在當(dāng)前設(shè)備上,我們需要EGL作為OpenGL ES與設(shè)備的橋梁。
需要知道的兩個(gè)方法
GLSurfaceView:渲染表面類(android.opengl.GLSurfaceView),自動(dòng)負(fù)責(zé)管理EGL執(zhí)行步驟,但用戶需要確定針對(duì)渲染表面 OpenGL ES 的版本,即調(diào)用 setEGLContextClientVersion(int version) 方法。隨后調(diào)用 setRenderer() 方法來(lái)為OpenGLES配置渲染表面。此外還有其他的 setEGL* 方法去配置上下文環(huán)境,例如渲染表面的 RGB 顏色分量的位深。
GLSurfaceView.Renderer:渲染器類(android.opengl.GLSurfaceView.Renderer),GLSurfaceView 需要通過(guò)渲染器對(duì)象完成實(shí)際的渲染操作,自定義渲染器對(duì)象需要繼承 Renderer 接口類,并實(shí)現(xiàn)三個(gè)方法:onSurfaceCreated()、onSurfaceChanged()和onDrawFrame()。
在Android中使用OpenGL ES的步驟:
- 創(chuàng)建
GLSurfaceView組件,使用 Activity 來(lái)顯示 GLSurfaceView 組件。 - 為 GLSurfaceView 配置渲染類
GLSurfaceView.Renderer,實(shí)現(xiàn)GLSurfaceView.Renderer接口并重寫3個(gè)方法。- onSurfaceCreated():當(dāng)Surface被第一次創(chuàng)建或從其他Activity切換回來(lái)都會(huì)調(diào)用此方法,方法中還可以初始化OpenGLES圖形(背景色)。
- onSurfaceChanged():在Surface被創(chuàng)建后,每次Surface尺寸變化,還有屏幕橫豎切換都會(huì)調(diào)用此方法。
- onDrawFrame():每繪制一幀都會(huì)調(diào)用此方法,在這個(gè)方法中必須繪制點(diǎn)什么,即使只是清空屏幕。因?yàn)槿绻裁炊紱](méi)畫,會(huì)導(dǎo)致屏幕不斷閃爍。重點(diǎn):此方法是繪制圖形的主要執(zhí)行點(diǎn)。
- 調(diào)用GLSurfaceView組件的
setRenderer()方法指定Renderer對(duì)象,該Renderer對(duì)象會(huì)完成GLSurfaceView里的3D圖形的繪制。
例子1:簡(jiǎn)單的程序+修改背景顏色 OpenGLESVersion
- 創(chuàng)建GLSurfaceView實(shí)例,檢查設(shè)備版本,Activity生命周期,配置上下文。
- 創(chuàng)建Renderer類,實(shí)現(xiàn)渲染方法。
- 效果展示。
1.創(chuàng)建GLSurfaceView實(shí)例
我們通過(guò) GLSurfaceView 來(lái)初始化 OpenGLES,如配置顯示設(shè)備 Display 以及在后臺(tái)線程中渲染。在此之前,我們需要對(duì)設(shè)備的進(jìn)行版本檢查,以及在 Android Activity 生命周期的維護(hù)、渲染請(qǐng)求方式進(jìn)行配置。最后才會(huì)配置這個(gè) Surface 視圖和傳入自定義 Renderer 類。
public class VersionActivity extends AppCompatActivity {
private GLSurfaceView surfaceView;
private boolean rendererSet = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//檢查OpenGl ES版本
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
//獲取版本號(hào)
int VersionNum = configurationInfo.reqGlEsVersion;
//輸出196608 16進(jìn)制=0x30000 3.0版本
if (VersionNum >= 196608) {
Toast.makeText(this, "OpenGLES version is 3.0 or more", Toast.LENGTH_SHORT).show();
rendererSet = true;
//執(zhí)行3.0版本的方法
}
//輸出131072 16進(jìn)制=0x20000 2.0版本
else if (VersionNum >= 131072 && VersionNum < 196608) {
Toast.makeText(this, "OpenGLES version is 2.0", Toast.LENGTH_SHORT).show();
rendererSet = true;
//執(zhí)行2.0版本的方法, 配置ES 2.0的上下文
surfaceView = new GLSurfaceView(this);
//確定針對(duì)渲染表面 OpenGL ES 的版本
surfaceView.setEGLContextClientVersion(2);
//1.連續(xù)刷新頻率不停渲染,0.按請(qǐng)求來(lái)渲染
surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
surfaceView.setRenderer(new GLES20Renderer());
setContentView(surfaceView);
} else {
Toast.makeText(this, "Current devices do not support OpenGLES", Toast.LENGTH_SHORT).show();
return;
}
}
@Override
protected void onPause() {
super.onPause();
if (rendererSet) {
surfaceView.onPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (rendererSet) {
surfaceView.onResume();
}
}
}
注意:渲染線程方式setRenderMode:
1.RENDERMODE_CONTINUOUSLY按設(shè)備刷新頻率不斷地渲染。
0.RENDERMODE_WHEN_DIRTY按請(qǐng)求方式來(lái)渲染。
2.創(chuàng)建Renderer類
在GLSurfaceView中傳入了一個(gè)自定義Renderer類,那么Renderer是一個(gè)渲染器,他需要重寫3個(gè)方法來(lái)實(shí)現(xiàn)渲染的整個(gè)過(guò)程。
public class GLES20Renderer implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//第一次創(chuàng)建或切換回來(lái)都會(huì)調(diào)用此方法
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
//每次Surface尺寸變化,比如屏幕橫豎切換都會(huì)調(diào)用此方法
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
//每繪制一幀都會(huì)調(diào)用此方法
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
}
-
onSurfaceCreated:其中的
glClearColor是設(shè)置清空屏幕用的顏色,四個(gè)參數(shù):紅綠藍(lán)透明,都是float類型,最大值為1,最小值為0。 -
onSurfaceChanged:其中的
glViewport是設(shè)置視口的尺寸,告訴OpenGLES用來(lái)顯示Surface的大小。 -
onDrawFrame:其中的
glClear(GL_COLOR_BUFFER_BIT)表示清空屏幕,并會(huì)用glClearColor再次填充整個(gè)屏幕。
問(wèn):參數(shù)中的
GL10是什么?
GL10是OpenGLES 1.0的API遺留下來(lái)的。但是要編寫使用OpenGLES1.0的渲染器,就用這個(gè)參數(shù)。但是對(duì)于OpenGLES2.0就直接通過(guò)靜態(tài)方法GLES20來(lái)直接獲取。OpenGLES3.0也是直接使用GLES30。
3.結(jié)果
當(dāng)運(yùn)行這個(gè)Activity的時(shí)候,會(huì)看到屏幕渲染上了一層藍(lán)色背景色,這也就是我們?cè)趏nSurfaceCreated中設(shè)置的glClearColor方法。

總結(jié)
這雖然是學(xué)習(xí)OpenGLES20的第一課,只學(xué)習(xí)了GLSurfaceView和Renderer渲染器,但有了整個(gè)程序的大體框架,是最接下來(lái)的學(xué)習(xí)有著大大的幫助。
參考文獻(xiàn)
- 《Android三維程序設(shè)計(jì)》
- 《OpenGL ES 應(yīng)用開(kāi)發(fā)實(shí)踐指南》
- https://blog.csdn.net/matrix_laboratory/article/details/50897183
- http://www.itdecent.cn/nb/8716340
- http://www.itdecent.cn/p/a94c8ed639c7
- 內(nèi)容講得比較清晰,還有前提點(diǎn)https://blog.csdn.net/zhang_he_xiang/article/details/85015357
為什么要使用OpenGL ES
通常來(lái)說(shuō),計(jì)算機(jī)系統(tǒng)中 CPU、GPU 是協(xié)同工作的。CPU 計(jì)算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會(huì)按照 VSync 信號(hào)逐行讀取幀緩沖區(qū)的數(shù)據(jù),經(jīng)過(guò)可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。所以,盡可能讓 CPU 和 GPU 各司其職發(fā)揮作用是提高渲染效率的關(guān)鍵。
正如我們之前提到過(guò),OpenGL 正是給我們提供了訪問(wèn) GPU 的能力,不僅如此,它還引入了緩存(Buffer)這個(gè)概念,大大提高了處理效率。
從一個(gè)內(nèi)存區(qū)域復(fù)制到另一個(gè)內(nèi)存區(qū)域的速度是相對(duì)較慢的,并且在內(nèi)存復(fù)制的過(guò)程中,CPU 和 GPU 都不能處理這區(qū)域內(nèi)存,避免引起錯(cuò)誤。此外,CPU / GPU 執(zhí)行計(jì)算的速度是很快的,而內(nèi)存的訪問(wèn)是相對(duì)較慢的,這也導(dǎo)致處理器的性能處于次優(yōu)狀態(tài),這種狀態(tài)叫做 數(shù)據(jù)饑餓,簡(jiǎn)單來(lái)說(shuō)就是空有一身本事卻無(wú)用武之地。
針對(duì)此,OpenGL 為了提升渲染的性能,為兩個(gè)內(nèi)存區(qū)域間的數(shù)據(jù)交換定義了緩存。緩存是指 GPU 能夠控制和管理的連續(xù) RAM。程序從 CPU 的內(nèi)存復(fù)制數(shù)據(jù)到 OpenGL ES 的緩存。通過(guò)獨(dú)占緩存,GPU 能夠盡可能以有效的方式讀寫內(nèi)存。 這也意味著 GPU 使用緩存中的數(shù)據(jù)工作的同時(shí),運(yùn)行在 CPU 中的程序可以繼續(xù)執(zhí)行。