OpenGL ES

Android 支援透過 Open Graphics Library (OpenGL®) 提供高效能 2D 和 3D 圖形,特別是 OpenGL ES API。OpenGL 是跨平台圖形 API,可為 3D 圖形處理硬體指定標準軟體介面。OpenGL ES 是適用於嵌入裝置的 OpenGL 規格的變種版本。Android 支援多種 OpenGL ES API 版本:

  • OpenGL ES 1.0 和 1.1 - 此 API 規格為 Android 1.0 以上版本。
  • OpenGL ES 2.0 - Android 2.2 (API 級別 8) 以上版本支援此 API 規格。
  • OpenGL ES 3.0 - Android 4.3 (API 級別 18) 以上版本支援此 API 規格。
  • OpenGL ES 3.1 - Android 5.0 (API 級別 21) 以上版本支援此 API 規格。

注意:無論 Android 平台版本為何,除非裝置製造商提供這個圖形管道的實作,否則裝置無法支援 OpenGL ES 3.0 API。如果您在資訊清單中指定 OpenGL ES 3.0 要求,可以確定該版本會顯示在裝置上。如果您指定需要使用較低層級的版本,但有 3.0 版功能可用,請在執行期間查看,瞭解裝置支援的 OpenGL 版本。如要瞭解相關做法,請參閱「檢查 OpenGL ES 版本」一文。

注意:Android 架構提供的特定 API 與 J2ME JSR239 OpenGL ES API 類似,但並非完全相同。如果您熟悉 J2ME JSR239 規格,請特別留意變化版本。

亦請參閱

基本資訊

Android 透過其架構 API 和原生開發套件 (NDK) 支援 OpenGL。本主題著重在 Android 架構介面。如要進一步瞭解 NDK,請參閱 Android NDK

Android 架構中有兩種基礎類別,可讓您使用 OpenGL ES API 建立及操控圖形:GLSurfaceViewGLSurfaceView.Renderer。如果您的目標是在 Android 應用程式中使用 OpenGL,建議您優先考慮如何在活動中實作這些類別。

GLSurfaceView
此類別是一種 View,可讓您使用 OpenGL API 呼叫繪製及操控物件,與 SurfaceView 的功能類似。如要使用這個類別,請建立 GLSurfaceView 的執行個體,並在其中新增 Renderer。不過,如果您想擷取觸控螢幕事件,則應擴充 GLSurfaceView 類別以實作觸控事件監聽器,如 OpenGL 訓練課程「回應觸控事件」所示。
GLSurfaceView.Renderer
這個介面定義在 GLSurfaceView 中繪製圖形所需的方法。您必須以獨立類別的形式提供這個介面的實作,並使用 GLSurfaceView.setRenderer() 將其附加至 GLSurfaceView 執行個體。

GLSurfaceView.Renderer 介面需要您實作下列方法:

  • onSurfaceCreated():建立 GLSurfaceView 時,系統會呼叫此方法一次。請使用這個方法執行只須執行一次的動作,例如設定 OpenGL 環境參數或初始化 OpenGL 圖形物件。
  • onDrawFrame():每次重新繪製 GLSurfaceView 時,系統都會呼叫這個方法。請使用這個方法做為繪製 (及重新繪製) 圖形物件的主要執行點。
  • onSurfaceChanged():當 GLSurfaceView 幾何圖形改變 (包括 GLSurfaceView 尺寸或裝置螢幕方向改變) 時,系統會呼叫這個方法。舉例來說,當裝置從直向改為橫向時,系統會呼叫這個方法。請使用這個方法來回應 GLSurfaceView 容器中的變更。

OpenGL ES 套件

使用 GLSurfaceViewGLSurfaceView.Renderer 建立 OpenGL ES 的容器檢視畫面後,就可以開始使用下列類別呼叫 OpenGL API:

如果您想立即開始使用 OpenGL ES 建構應用程式,請按照「使用 OpenGL ES 顯示圖形」類別操作。

宣告 OpenGL 需求

如果您的應用程式使用了部分裝置無法使用的 OpenGL 功能,則必須在 AndroidManifest.xml 檔案中加入這些需求。以下是最常見的 OpenGL 資訊清單宣告:

  • OpenGL ES 版本需求 - 如果應用程式需要特定版本的 OpenGL ES,您必須在資訊清單中新增下列設定,宣告該需求。

    OpenGL ES 2.0:

    <!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

    加入這個宣告後,Google Play 就會禁止 您的應用程式安裝在不支援 OpenGL ES 2.0 的裝置上。如果應用程式是專為支援 OpenGL ES 3.0 的裝置所設計,您也可以在資訊清單中指定這項資訊:

    OpenGL ES 3.0:

    <!-- Tell the system this app requires OpenGL ES 3.0. -->
    <uses-feature android:glEsVersion="0x00030000" android:required="true" />
    

    針對 OpenGL ES 3.1:

    <!-- Tell the system this app requires OpenGL ES 3.1. -->
    <uses-feature android:glEsVersion="0x00030001" android:required="true" />
    

    注意:OpenGL ES 3.x API 與 2.0 API 回溯相容,因此您可以在應用程式中實作 OpenGL ES 時更具彈性。在資訊清單中宣告 OpenGL ES 2.0 API 為必要條件,您可以使用該 API 版本做為預設值,檢查 3.x API 在執行階段是否可用,然後使用 OpenGL ES 3.x 功能 (如果裝置支援的話)。如要進一步瞭解如何檢查裝置支援的 OpenGL ES 版本,請參閱「檢查 OpenGL ES 版本」。

  • 紋理壓縮規定 - 如果您的應用程式使用紋理壓縮格式,您必須使用 <supports-gl-texture> 在資訊清單檔案中宣告應用程式支援的格式。如要進一步瞭解可用的紋理壓縮格式,請參閱「紋理壓縮支援」一文。

    在資訊清單中宣告紋理壓縮需求條件,會隱藏應用程式,以免裝置不支援至少一個宣告的壓縮類型。如要進一步瞭解 Google Play 如何篩選紋理壓縮作業,請參閱 <supports-gl-texture> 說明文件的「 Google Play 和紋理壓縮篩選功能」一節。

已繪製物件的對應座標

在 Android 裝置上顯示圖像的其中一項基本問題,就是畫面的大小和形狀可能有所不同。OpenGL 會假設採用方形、統一座標系統,並根據預設,將這些座標繪製到一般非正方形螢幕上,就像是完美的方形一樣。

圖 1. 對應至一般 Android 裝置螢幕的預設 OpenGL 座標系統 (左側)。

上圖是左側 OpenGL 頁框假設的統一座標系統,以及右側以橫向模式實際對應至一般裝置螢幕的方式。如要解決這個問題,您可以套用 OpenGL 投影模式和相機檢視畫面來轉換座標,讓圖形物件在任何螢幕上都能維持正確的比例。

如要套用投影和相機檢視畫面,請建立投影矩陣和相機檢視矩陣,並套用至 OpenGL 算繪管道。投影矩陣會重新計算圖形的座標,使其正確對應到 Android 裝置螢幕。相機檢視矩陣會建立轉換,從特定眼睛位置算繪物件。

OpenGL ES 1.0 中的投影和相機檢視畫面

在 ES 1.0 API 中,您可以建立每個矩陣並將其加入 OpenGL 環境,藉此套用投影和相機檢視畫面。

  1. 投影矩陣 - 使用裝置螢幕的幾何圖形建立投影矩陣,以便重新計算物件座標,以便使用正確比例繪製。以下程式碼範例示範如何修改 GLSurfaceView.Renderer 實作的 onSurfaceChanged() 方法,根據螢幕的長寬比建立投影矩陣,並套用至 OpenGL 算繪環境。

    Kotlin

    override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
        gl.apply {
            glViewport(0, 0, width, height)
    
            // make adjustments for screen ratio
            val ratio: Float = width.toFloat() / height.toFloat()
    
            glMatrixMode(GL10.GL_PROJECTION)            // set matrix to projection mode
            glLoadIdentity()                            // reset the matrix to its default state
            glFrustumf(-ratio, ratio, -1f, 1f, 3f, 7f)  // apply the projection matrix
        }
    }
    

    Java

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
    
        // make adjustments for screen ratio
        float ratio = (float) width / height;
        gl.glMatrixMode(GL10.GL_PROJECTION);        // set matrix to projection mode
        gl.glLoadIdentity();                        // reset the matrix to its default state
        gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);  // apply the projection matrix
    }
    
  2. 相機轉換矩陣 - 在您使用投影矩陣調整座標系統後,必須一併套用相機檢視畫面。下列程式碼範例說明如何修改 GLSurfaceView.Renderer 實作的 onDrawFrame() 方法,以套用模型檢視畫面,並使用 GLU.gluLookAt() 公用程式建立模擬攝影機位置的檢視轉換。

    Kotlin

    override fun onDrawFrame(gl: GL10) {
        ...
        gl.apply {
            // Set GL_MODELVIEW transformation mode
            glMatrixMode(GL10.GL_MODELVIEW)
            glLoadIdentity()                     // reset the matrix to its default state
        }
    
        // When using GL_MODELVIEW, you must set the camera view
        GLU.gluLookAt(gl, 0f, 0f, -5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
        ...
    }
    

    Java

    public void onDrawFrame(GL10 gl) {
        ...
        // Set GL_MODELVIEW transformation mode
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();                      // reset the matrix to its default state
    
        // When using GL_MODELVIEW, you must set the camera view
        GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        ...
    }
    

OpenGL ES 2.0 以上版本中的投影和相機檢視畫面

在 ES 2.0 和 3.0 API 中,您必須先新增矩陣成員至圖形物件的頂點著色器,才能套用投影和相機檢視畫面。新增此矩陣成員後,您就可以產生投影和相機檢視矩陣,並套用至物件。

  1. 新增矩陣至頂點著色器:為檢視畫面投影矩陣建立變數,並將其做為著色器位置的乘數。在以下的頂點著色器程式碼範例中,隨附的 uMVPMatrix 成員可讓您將投影和攝影機檢視矩陣套用至使用這個著色器的物件座標。

    Kotlin

    private val vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n"
    

    Java

    private final String vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n";
    

    注意:上述範例在頂點著色器中定義單一轉換矩陣成員,您可以套用合併的投影矩陣和相機檢視矩陣。視應用程式需求而定,建議您在頂點著色器中定義個別的投影矩陣和攝影機檢視矩陣成員,以便獨立變更。

  2. 存取著色器矩陣 - 在頂點著色器中建立掛鉤以套用投影和相機檢視畫面後,您就可以存取該變數來套用投影和相機檢視矩陣。以下程式碼說明如何修改 GLSurfaceView.Renderer 實作的 onSurfaceCreated() 方法,以存取上述頂點著色器中定義的矩陣變數。

    Kotlin

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix")
        ...
    }
    

    Java

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        ...
    }
    
  3. 建立投影和相機檢視矩陣 - 產生要套用圖形物件的投影和檢視矩陣。以下範例程式碼說明如何修改 GLSurfaceView.Renderer 實作的 onSurfaceCreated()onSurfaceChanged() 方法,以根據裝置螢幕長寬比建立攝影機檢視矩陣和投影矩陣。

    Kotlin

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(vMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
    }
    
    override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    
        val ratio: Float = width.toFloat() / height.toFloat()
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
    }
    

    Java

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(vMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    }
    
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    
        float ratio = (float) width / height;
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }
    
  4. 套用投影和相機檢視矩陣 - 如要套用投影和相機檢視畫面轉換,請將矩陣相乘,然後設為頂點著色器。下列程式碼範例說明如何修改 GLSurfaceView.Renderer 實作的 onDrawFrame() 方法,結合上述程式碼中建立的投影矩陣和相機檢視畫面,然後套用至 OpenGL 算繪的圖像物件。

    Kotlin

    override fun onDrawFrame(gl: GL10) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0)
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0)
    
        // Draw objects
        ...
    }
    

    Java

    public void onDrawFrame(GL10 unused) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0);
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0);
    
        // Draw objects
        ...
    }
    

如需如何使用 OpenGL ES 2.0 套用投影和相機檢視畫面的完整範例,請參閱「使用 OpenGL ES 顯示圖形」類別。

形狀和眨眼

在 OpenGL 中,形狀的表面是由三維空間中的三個或更多點定義的表面。由三個或更多的 3D 點 (在 OpenGL 中稱為頂點) 有一個正面和一個背面。如何分辨哪張臉孔位於前方,哪些是背面?好問題。答案必須與旋風 (也就是您定義形狀點的方向) 有關。

三角形的座標

圖 1. 座標清單轉譯為逆時針繪圖順序的插圖。

在這個範例中,三角形的點都按照順序定義,使點以逆時針方向繪製。繪製這些座標的順序決定了形狀的彎曲方向。根據預設,在 OpenGL 中,逆時針繪製的錶面為正面。圖 1 所示的三角形已定義,可讓您查看形狀的正面 (如 OpenGL 解讀),另一邊是背面。

為什麼知道形狀的正面很重要?答案必須透過 OpenGL 的常用功能 (稱為臉部校正) 來回答。人臉解鎖功能是 OpenGL 環境的選項,可讓轉譯管道忽略 (而非計算或繪製) 形狀的背面,藉此節省時間、記憶體和處理週期:

Kotlin

gl.apply {
    // enable face culling feature
    glEnable(GL10.GL_CULL_FACE)
    // specify which faces to not draw
    glCullFace(GL10.GL_BACK)
}

Java

// enable face culling feature
gl.glEnable(GL10.GL_CULL_FACE);
// specify which faces to not draw
gl.glCullFace(GL10.GL_BACK);

如果您在嘗試使用臉部辨識功能時,不知道形狀的正面和背面為何,OpenGL 圖形會看起來有些微薄或完全無法顯示。因此,請一律以逆時針繪圖順序定義 OpenGL 形狀的座標。

注意:您可以設定 OpenGL 環境將順時針視為前端,但這樣需要較多程式碼,而且可能會在您尋求協助時可能混淆 OpenGL 開發人員。所以不要這麼做。

OpenGL 版本與裝置相容性

自 Android 1.0 起,已支援 OpenGL ES 1.0 和 1.1 API 規格。 從 Android 2.2 (API 級別 8) 開始,此架構支援 OpenGL ES 2.0 API 規範。大多數 Android 裝置都支援 OpenGL ES 2.0,建議使用 OpenGL 開發新應用程式。OpenGL ES 3.0 支援 Android 4.3 (API 級別 18) 以上版本,但在提供 OpenGL ES 3.0 API 的裝置上支援。如要進一步瞭解支援特定 OpenGL ES 版本的 Android 裝置相對數量,請參閱 OpenGL ES 版本資訊主頁

使用 OpenGL ES 1.0/1.1 API 進行圖形程式設計與 2.0 以上版本相比,明顯不同。1.x 版本的 API 有更加便利的方法和固定的圖形管道,OpenGL ES 2.0 和 3.0 API 則能夠透過 OpenGL 著色器進一步直接控制管道。請務必審慎考量圖像需求,並選擇最適合應用程式的 API 版本。詳情請參閱選擇 OpenGL API 版本

OpenGL ES 3.0 API 提供比 2.0 API 更多的功能和效能,也具有回溯相容性。也就是說,您可以編寫指定 OpenGL ES 2.0 的應用程式,並在有 OpenGL ES 3.0 圖形功能可用時加入特定條件。如要進一步瞭解如何檢查 3.0 API 的可用性,請參閱檢查 OpenGL ES 版本

紋理壓縮支援

紋理壓縮可減少記憶體需求,並更有效率地使用記憶體頻寬,進而大幅提高 OpenGL 應用程式的效能。Android 架構以標準功能形式提供 ETC1 壓縮格式的支援,包括 ETC1Util 公用程式類別和 etc1tool 壓縮工具 (位於 Android SDK 的 <sdk>/tools/)。如需使用紋理壓縮的 Android 應用程式範例,請參閱 Android SDK (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/) 中的 CompressedTextureActivity 程式碼範例。

注意:大多數 Android 裝置都支援 ETC1 格式,但不保證一定可供使用。如要確認裝置是否支援 ETC1 格式,請呼叫 ETC1Util.isETC1Supported() 方法。

注意:ETC1 紋理壓縮格式不支援具有透明度 (Alpha 管道) 的紋理。如果應用程式需要具有透明度的紋理,則建議您調查目標裝置上可用的其他紋理壓縮格式。

使用 OpenGL ES 3.0 API 時,保證可以使用 ETC2/EAC 紋理壓縮格式。這個紋理格式提供高品質的視覺品質良好的壓縮比率,而且該格式也支援透明度 (Alpha 管道)。

除了 ETC 格式以外,Android 裝置還能根據其 GPU 晶片組和 OpenGL 實作方式,提供不同的紋理壓縮支援。您應在指定的裝置上調查紋理壓縮支援情形,判斷應用程式應支援的壓縮類型。如要判斷特定裝置支援的紋理格式,您必須查詢裝置並查看 OpenGL 擴充功能名稱,藉此識別裝置支援的紋理壓縮格式 (以及其他 OpenGL 功能)。部分常見支援的紋理壓縮格式如下:

  • ATITC (ATC) - ATI 紋理壓縮 (ATITC 或 ATC) 支援多種裝置,並支援包含及不含 Alpha 通道的 RGB 紋理的固定頻率壓縮功能。這個格式可能會以多個 OpenGL 擴充功能名稱表示,例如:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC - PowerVR 紋理壓縮 (PVRTC) 適用於多種裝置,並支援每個像素的 2 位元和 4 位元紋理 (無論是否含有 Alpha 通道)。格式以下列 OpenGL 擴充功能名稱表示:
    • GL_IMG_texture_compression_pvrtc
  • S3TC (DXTn/DXTC) - S3 紋理壓縮 (S3TC) 有多種格式變化 (DXT1 到 DXT5),而且較不普遍。此格式支援使用 4 位元 Alpha 或 8 位元 Alpha 通道的 RGB 紋理。這些格式以下列 OpenGL 擴充功能名稱表示:
    • GL_EXT_texture_compression_s3tc
    部分裝置僅支援 DXT1 格式變化;這項有限支援以下列 OpenGL 擴充功能名稱表示:
    • GL_EXT_texture_compression_dxt1
  • 3DC - 3DC 紋理壓縮 (3DC) 是較不普遍的格式,支援使用 Alpha 通道的 RGB 紋理,此格式以下列 OpenGL 擴充功能名稱表示:
    • GL_AMD_compressed_3DC_texture

警告:部分裝置不支援這些紋理壓縮格式。這些格式的支援情形會因製造商和裝置而異。如要瞭解如何判斷特定裝置上的紋理壓縮格式,請參閱下一節。

注意:決定應用程式支援的紋理壓縮格式後,請務必在資訊清單中使用 <supports-gl-texture> 宣告這些格式。使用這項宣告可讓外部服務 (例如 Google Play) 進行篩選,讓應用程式只能在支援應用程式所需格式的裝置上安裝。詳情請參閱 OpenGL 資訊清單宣告

判斷 OpenGL 擴充功能

OpenGL 的實作方式因 Android 裝置支援的 OpenGL ES API 擴充功能而異。這些擴充功能包含紋理壓縮,但通常也會包含 OpenGL 功能集的其他擴充功能。

為判斷特定裝置支援哪些紋理壓縮格式和其他 OpenGL 擴充功能:

  1. 在目標裝置上執行下列程式碼,判斷支援的紋理壓縮格式:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

    String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
    

    警告:這項呼叫的結果會因裝置型號而異!您必須在多個目標裝置上執行此呼叫,以判斷最常見的壓縮類型。

  2. 查看這個方法的輸出內容,判斷裝置支援哪些 OpenGL 擴充功能。

Android 擴充功能包 (AEP)

AEP 可確保您的應用程式支援一組以上的標準化 OpenGL 擴充功能,而且不僅是 OpenGL 3.1 規格所述的核心集外。將這些擴充功能包裝在一起,有助於在各種裝置上取得一致的功能組合,同時可讓開發人員充分利用最新裁剪的行動裝置 GPU 裝置。

此外,AEP 也改善了在片段著色器中對圖片、著色器儲存空間緩衝區和原子計數器的支援功能。

為了讓您的應用程式使用 AEP,應用程式的資訊清單必須宣告需要 AEP。此外,平台版本也必須支援該平台。

在資訊清單中宣告 AEP 規定,如下所示:

<uses-feature android:name="android.hardware.opengles.aep"
              android:required="true" />

如要驗證平台版本是否支援 AEP,請使用 hasSystemFeature(String) 方法,並傳入 FEATURE_OPENGLES_EXTENSION_PACK 做為引數。以下程式碼片段示範如何執行這項作業:

Kotlin

var deviceSupportsAEP: Boolean =
        packageManager.hasSystemFeature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK)

Java

boolean deviceSupportsAEP = getPackageManager().hasSystemFeature
     (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);

如果方法傳回 true,表示支援 AEP。

如要進一步瞭解 AEP,請前往 Khronos OpenGL ES Registry 頁面。

檢查 OpenGL ES 版本

Android 裝置提供多種 OpenGL ES 版本。您可以在資訊清單中指定應用程式所需的 API 最低版本,但您也可以同時使用新版 API 的功能。例如,OpenGL ES 3.0 API 與 API 2.0 版本回溯相容,因此您可能需要編寫應用程式,讓應用程式使用 OpenGL ES 3.0 功能;但如果無法使用 OpenGL ES 3.0,便可改回使用 2.0 API。

如要使用 OpenGL ES 功能,所用版本高於應用程式資訊清單要求的最低版本,應用程式應檢查裝置上可用的 API 版本。您可以選擇以下其中一種方法:

  1. 嘗試建立較高層級的 OpenGL ES 結構定義 (EGLContext) 並檢查結果。
  2. 建立最低支援的 OpenGL ES 結構定義,並查看版本值。

下列程式碼範例示範如何透過建立 EGLContext 並檢查結果,來檢查可用的 OpenGL ES 版本。以下範例說明如何檢查 OpenGL ES 3.0 版本:

Kotlin

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
private class ContextFactory : GLSurfaceView.EGLContextFactory {

    override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): EGLContext {

        Log.w(TAG, "creating OpenGL ES $glVersion context")
        return egl.eglCreateContext(
                display,
                eglConfig,
                EGL10.EGL_NO_CONTEXT,
                intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
        ) // returns null if 3.0 is not supported
    }
}

Java

private static double glVersion = 3.0;

private static class ContextFactory implements GLSurfaceView.EGLContextFactory {

  private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

  public EGLContext createContext(
          EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {

      Log.w(TAG, "creating OpenGL ES " + glVersion + " context");
      int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
              EGL10.EGL_NONE };
      // attempt to create a OpenGL ES 3.0 context
      EGLContext context = egl.eglCreateContext(
              display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
      return context; // returns null if 3.0 is not supported;
  }
}

如果上述 createContext() 方法傳回空值,則程式碼應改為建立 OpenGL ES 2.0 結構定義,改回只使用該 API。

下列程式碼範例說明如何透過建立最低支援內容,再檢查版本字串的方式,查看 OpenGL ES 版本:

Kotlin

// Create a minimum supported OpenGL ES context, then check:
gl.glGetString(GL10.GL_VERSION).also {
    Log.w(TAG, "Version: $it")
}
 // The version format is displayed as: "OpenGL ES <major>.<minor>"
 // followed by optional content provided by the implementation.

Java

// Create a minimum supported OpenGL ES context, then check:
String version = gl.glGetString(GL10.GL_VERSION);
Log.w(TAG, "Version: " + version );
// The version format is displayed as: "OpenGL ES <major>.<minor>"
// followed by optional content provided by the implementation.

透過這個方法,如果您發現裝置支援較高層級的 API 版本,就必須刪除最低 OpenGL ES 結構定義,並使用較高可用的 API 版本建立新結構定義。

選擇 OpenGL API 版本

OpenGL ES 1.0 API 版本 (以及 1.1 擴充功能)、2.0 版及 3.0 版都提供高效能的圖形介面,方便您建立 3D 遊戲、視覺化內容和使用者介面。OpenGL ES 2.0 和 3.0 的圖形程式設計大致類似,其中 3.0 版代表 2.0 API 的超集,並提供更多功能。OpenGL ES 1.0/1.1 API 與 OpenGL ES 2.0 和 3.0 的程式設計方法有顯著差異,因此開發人員在開始使用這些 API 進行開發作業之前,應先審慎考量以下因素:

  • 效能 - 一般來說,OpenGL ES 2.0 和 3.0 的圖形效能比 ES 1.0/1.1 API 更快。不過,由於硬體製造商的 OpenGL ES 圖形管道實作方式不同,效能差異可能因執行 OpenGL 應用程式的 Android 裝置而異。
  • 裝置相容性:開發人員應考量客戶可用的裝置類型、Android 版本和 OpenGL ES 版本。如要進一步瞭解各裝置的 OpenGL 相容性,請參閱「OpenGL 版本和裝置相容性」一節。
  • 程式設計便利 - OpenGL ES 1.0/1.1 API 提供固定的函式管道和便利功能,OpenGL ES 2.0 或 3.0 API 均不支援這些功能。剛開始接觸 OpenGL ES 的開發人員可能會發現 1.0/1.1 版程式設計速度更快、更方便。
  • 圖形控制 - OpenGL ES 2.0 和 3.0 API 透過使用著色器提供可完全程式化的管道,藉此提升控製程度。有了更直接的圖形處理管道控制能力,開發人員就能使用 1.0/1.1 API 產生難以生成的效果。
  • 紋理支援 - OpenGL ES 3.0 API 提供最佳紋理壓縮支援,因為可確保符合資訊透明度的 ETC2 壓縮格式。1.x 和 2.0 API 實作通常支援 ETC1,但這個紋理格式不支援透明度,因此通常您必須以目標裝置支援的其他壓縮格式提供資源。詳情請參閱「紋理壓縮支援」。

雖然效能、相容性、便利性、控制和其他因素都可能會影響您的決策,但您應根據自己認為能提供使用者最佳體驗的因素來選擇 OpenGL API 版本。