OpenGL ES

Android は、Open Graphics Library(OpenGL®)、特に OpenGL ES API による高性能 2D および 3D グラフィックをサポートしています。OpenGL は、3D グラフィック処理ハードウェアの標準ソフトウェア インターフェースを定める、クロス プラットフォームのグラフィック API です。OpenGL ES は OpenGL 仕様のフレーバーで、組み込みデバイスを対象としています。Android は OpenGL ES API の複数のバージョンをサポートしています。

  • OpenGL ES 1.0 と 1.1 - この API 仕様は Android 1.0 以降でサポートされています。
  • OpenGL ES 2.0 - この API 仕様は Android 2.2(API レベル 8)以降でサポートされています。
  • OpenGL ES 3.0 - この API 仕様は Android 4.3(API レベル 18)以降でサポートされています。
  • OpenGL ES 3.1 - この API 仕様は Android 5.0(API レベル 21)以降でサポートされています。

注意: Android プラットフォームのバージョンにかかわらず、デバイス メーカーが OpenGL ES 3.0 API の実装を提供しない限り、デバイスは 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 という 2 つの基本クラスがあります。Android アプリで OpenGL を使用することが目的の場合は、まず、これらのクラスをアクティビティに実装する方法を理解する必要があります。

GLSurfaceView
このクラスは、OpenGL API 呼び出しを使用してオブジェクトを描画および操作できる View であり、機能的には SurfaceView と似ています。このクラスを使用するには、GLSurfaceView のインスタンスを作成して Renderer を追加します。ただし、タッチ スクリーン イベントをキャプチャする場合は、OpenGL トレーニング レッスンのタッチイベントへの応答で説明されているように、GLSurfaceView クラスを拡張してタッチリスナーを実装する必要があります。
GLSurfaceView.Renderer
このインターフェースは、GLSurfaceView でグラフィックを描画するために必要なメソッドを定義します。このインターフェースの実装を別のクラスとして提供し、GLSurfaceView.setRenderer() を使用して GLSurfaceView インスタンスに接続する必要があります。

GLSurfaceView.Renderer インターフェースでは、次のメソッドを実装する必要があります。

  • onSurfaceCreated(): GLSurfaceView の作成時に、このメソッドが 1 回呼び出されます。このメソッドを使用して、OpenGL 環境パラメータの設定や OpenGL グラフィック オブジェクトの初期化など、1 回だけ実行する必要があるアクションを実行します。
  • onDrawFrame(): GLSurfaceView が再描画されるごとに、システムがこのメソッドを呼び出します。このメソッドは、グラフィック オブジェクトの描画(および再描画)を行う際の主な実行ポイントとして使用します。
  • onSurfaceChanged(): GLSurfaceView のサイズやデバイス画面の向きの変更など、GLSurfaceView ジオメトリが変更されたときに、システムがこのメソッドを呼び出します。たとえば、デバイスが縦向きから横向きに変わると、このメソッドが呼び出されます。GLSurfaceView コンテナの変更に対応するには、このメソッドを使用します。

OpenGL ES パッケージ

GLSurfaceViewGLSurfaceView.Renderer を使用して OpenGL ES のコンテナビューを確立したら、次のクラスを使用して OpenGL API の呼び出しを開始できます。

  • OpenGL ES 1.0/1.1 API パッケージ
  • OpenGL ES 2.0 API クラス
    • android.opengl.GLES20 - このパッケージは OpenGL ES 2.0 へのインターフェースを提供し、Android 2.2(API レベル 8)以降で使用できます。
  • OpenGL ES 3.0/3.1 API パッケージ
    • android.opengl - このパッケージは、OpenGL ES 3.0/3.1 クラスへのインターフェースを提供します。バージョン 3.0 は Android 4.3(API レベル 18)以降で使用できます。バージョン 3.1 は、Android 5.0(API レベル 21)以降で使用できます。

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> を使用して宣言する必要があります。利用可能なテクスチャ圧縮形式の詳細については、テクスチャ圧縮のサポートをご覧ください。

    マニフェストでテクスチャ圧縮要件を宣言すると、宣言した圧縮タイプの少なくとも 1 つをサポートしていないデバイスを使用するユーザーには、アプリが表示されなくなります。テクスチャ圧縮に対する Google Play フィルタリングの仕組みについては、<supports-gl-texture> ドキュメントの Google Play とテクスチャ圧縮フィルタリングのセクションをご覧ください。

描画オブジェクトの座標のマッピング

Android デバイスでグラフィックを表示する際の基本的な問題のひとつに、画面のサイズや形状が異なることがあります。OpenGL は正方形の均一な座標系を前提としており、デフォルトでは、正方形ではない画面上に、その座標が完全な正方形であるかのように描画されます。

図 1. デフォルトの OpenGL 座標系(左)は、一般的な Android デバイスの画面(右)にマッピングされています。

上の図は、左側の 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 API と ES 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 では、シェイプの面は 3 次元空間内の 3 つ以上の点によって定義される面です。3 つ以上の 3 次元のポイント(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 バージョンとデバイスの互換性

OpenGL ES 1.0 と 1.1 の API 仕様は、Android 1.0 以降でサポートされています。 Android 2.2(API レベル 8)以降、フレームワークは OpenGL ES 2.0 API 仕様をサポートしています。OpenGL ES 2.0 はほとんどの Android デバイスでサポートされており、OpenGL で開発する新しいアプリにおすすめです。OpenGL ES 3.0 は、OpenGL ES 3.0 API の実装を提供するデバイスで、Android 4.3(API レベル 18)以降でサポートされます。特定のバージョンの OpenGL ES をサポートする Android 搭載デバイスの相対数については、OpenGL ES バージョン ダッシュボードをご覧ください。

OpenGL ES 1.0/1.1 API によるグラフィック プログラミングは、2.0 以降のバージョンを使用した場合とは大きく異なります。API の 1.x バージョンは、より多くの便利なメソッドと固定グラフィック パイプラインを備えています。一方、OpenGL ES 2.0 API と 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 フレームワークは、ETC1Util ユーティリティ クラスや etc1tool 圧縮ツール(<sdk>/tools/ の Android SDK にあります)など、標準機能として ETC1 圧縮形式をサポートしています。テクスチャ圧縮を使用する Android アプリの例については、Android SDK(<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/)の CompressedTextureActivity コードサンプルをご覧ください。

注意: ETC1 形式はほとんどの Android デバイスでサポートされていますが、利用できる保証はありません。ETC1 形式がデバイスでサポートされているかどうかを確認するには、ETC1Util.isETC1Supported() メソッドを呼び出します。

注: ETC1 テクスチャ圧縮形式は、透明度(アルファ チャンネル)を持つテクスチャをサポートしていません。アプリケーションで透明なテクスチャを必要とする場合は、ターゲット デバイスで利用可能な他のテクスチャ圧縮形式を調査する必要があります。

OpenGL ES 3.0 API を使用する場合は、ETC2/EAC テクスチャ圧縮形式の利用が保証されています。このテクスチャ形式は、優れた画質で優れた圧縮率を実現します。また、透明度(アルファ チャンネル)もサポートしています。

ETC 形式以外にも、Android デバイスは GPU チップセットや OpenGL 実装に基づいて、さまざまなテクスチャ圧縮をサポートしています。ターゲットとするデバイスでのテクスチャ圧縮のサポート状況を調査して、アプリケーションがサポートする圧縮タイプを決定する必要があります。特定のデバイスでサポートされているテクスチャ形式を特定するには、デバイスにクエリを実行し、デバイスでサポートされているテクスチャ圧縮形式(およびその他の OpenGL 機能)を特定する OpenGL 拡張機能名を確認する必要があります。一般的にサポートされているテクスチャ圧縮形式は次のとおりです。

  • ATITC(ATC) - ATI テクスチャ圧縮(ATITC または ATC)はさまざまなデバイスで利用でき、アルファ チャンネルの有無にかかわらず RGB テクスチャの固定レート圧縮をサポートします。この形式は、次のような複数の OpenGL 拡張機能名で表される場合があります。
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC - PowerVR テクスチャ圧縮(PVRTC)はさまざまなデバイスで利用でき、アルファ チャネルの有無にかかわらず、ピクセルあたり 2 ビットおよび 4 ビットのテクスチャをサポートします。この形式は、次の OpenGL 拡張機能名で表されます。
    • GL_IMG_texture_compression_pvrtc
  • S3TC(DXTn/DXTC) - S3 テクスチャ圧縮(S3TC)には複数の形式バリエーション(DXT1 から DXT5)があり、あまり広く利用されていません。この形式は、4 ビットのアルファ チャネルまたは 8 ビットのアルファ チャネルの RGB テクスチャをサポートしています。これらの形式は、次の OpenGL 拡張機能名で表されます。
    • GL_EXT_texture_compression_s3tc
    一部のデバイスでは、DXT1 形式のバリエーションのみをサポートします。この限定的なサポートを、次の OpenGL 拡張機能名で表しています。
    • GL_EXT_texture_compression_dxt1
  • 3DC - 3DC テクスチャ圧縮(3DC)は、アルファ チャンネルを持つ RGB テクスチャをサポートする、あまり利用されていない形式です。この形式は、次の OpenGL 拡張機能名で表されます。
    • GL_AMD_compressed_3DC_texture

警告: これらのテクスチャ圧縮形式は、すべてのデバイスでサポートされていません。これらの形式のサポート状況は、製造元またはデバイスによって異なる場合があります。特定のデバイスでのテクスチャ圧縮形式を特定する方法については、次のセクションをご覧ください。

注:アプリがサポートするテクスチャ圧縮形式を決定したら、マニフェストで <supports-gl-texture> を使用してその形式を宣言してください。この宣言を使用すると、Google Play などの外部サービスでのフィルタリングが有効になり、アプリが必要とする形式をサポートするデバイスにのみアプリがインストールされます。詳しくは、OpenGL マニフェストの宣言をご覧ください。

OpenGL 拡張機能の決定

OpenGL の実装は、サポートされている OpenGL ES API の拡張機能の点で Android デバイスによって異なります。これらの拡張機能にはテクスチャ圧縮が含まれますが、通常は 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 は 2.0 バージョンの API と下位互換性があるため、OpenGL ES 3.0 の機能を使用するようにアプリケーションを作成できますが、3.0 API を使用できない場合は 2.0 API にフォールバックします。

アプリ マニフェストで必要とする最小バージョン以上のバージョンの OpenGL ES 機能を使用する前に、デバイスで利用できる API のバージョンをアプリで確認する必要があります。これには次の 2 つの方法があります。

  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() メソッドが null を返す場合は、代わりに 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 のバージョンは、ユーザーにとって最適なエクスペリエンスが得られると思われるものを選択してください。