Android向けOpenGL ES2の学習レッスン#4。 テクスチャー

始める前に



»OpenGL ESを初めて使用する場合は、前の3つのレッスン( 1 つ、2つ、 3つ)を最初に学習することをお勧めします

»この記事で使用されるコードの基本は、 ここここから取得されます



このレッスンの結果、イルカが海面の上にジャンプします。











テクスチャについて少し



テクスチャは、ポリゴンモデルの表面に重ねて、色、色、または浮き彫りのような錯覚を与えるラスターイメージです。 テクスチャの使用は、彫刻画像の表面の絵として簡単に想像できます。









テクスチャを使用すると、小さなサーフェスの詳細を再現することもできます。どのポリゴンを作成すると、リソースを過度に消費することがわかります。 たとえば、皮膚の傷跡、衣服のしわ、小さな石、壁や土の表面のその他の物体。



テクスチャサーフェスの品質は、テクセル(テクスチャの最小単位あたりのピクセル数)によって決まります。 テクスチャ自体は画像であるため、テクスチャの解像度とそのフォーマットが大きな役割を果たし、アプリケーションのグラフィックスの速度と品質に影響します。



テクスチャ座標



OpenGLでは、テクスチャ座標は通常(x、y)ではなく(s、t)または(u、v)座標で指定されます。 (s、t)はテクセルテクスチャで、ポリゴンに変換されます。



ほとんどのコンピューター座標表示システムでは、Y軸は下向きで、Xは右側にあるため、左上隅はポイント(0、0)の画像に対応しています。









一部のAndroidシステムでは、メモリは、辺が2のnの倍数であるテクスチャでのみ機能することを覚えておく必要があります。 そのため、512 x 512や1024 x 512など、ピクセル単位の適切なサイズのテクスチャを持つアトラスを作成する必要があります。 また、POTテクスチャ(POT-2のべき乗、つまり2のべき乗)を使用しない場合、ミップマップのタイリングまたは自動生成を適用できません。 この場合、タイリングとは、単一のテクスチャの繰り返しの繰り返しを指します。 幅が高さの2倍であっても、右下隅には常に座標(1,1)があります。 これは正規化座標と呼ばれます。



アプリケーションは多くの小さなテクスチャを使用することが多く、あるテクスチャから別のテクスチャへの切り替えは比較的遅いプロセスです。 したがって、このような状況では、多くの小さな画像の代わりに1つの大きな画像を使用することをお勧めします。 このような画像はテクスチャアトラスと呼ばれます。 サブテクスチャはUV変換を使用してオブジェクトにマッピングされ、アトラスの座標は画像のどの部分を使用するかを決定します。



アプリケーションには3つのテクスチャ(空、海、イルカ)があるため、サイズ1024x1024 png形式の1つのアトラスに結合されます。









ご覧のとおり、イルカの別の画像を追加しました(右下隅)。 次に、左側のものの代わりに遊んで接続することができます。 たくさんの空きスペースが残っているので、このアトラスは非常に貧弱に作られています。 最適な方法で画像をパックできるアルゴリズムとプログラムがあります。 たとえば、写真のように。









テクスチャのウェイト(占有メモリサイズ)は次の方法で決定できます。バイトに高さピクセルと幅ピクセルを掛けるので、サイズが1024 x 1024の32ビットテクスチャは4 * 1024 * 1024 = 4'194'304バイトになります。



1024 x 1024の16ビットテクスチャは2MBしか使用しないため、32ビットイメージを使用するかどうかを検討する必要があります。



ハードウェアテクスチャ圧縮があり、通常はテクスチャの重量を4倍減らすことができます。 ただし、現在これらの問題は主な問題ではなく、検討のために情報を渡すだけです。



このレッスンでは、GL_TEXTURE_2Dメソッドのみを使用します。これにより、プレーンにテクスチャを配置できます(6個の正方形で構成される拡張キューブのテクスチャで機能するGL_TEXTURE_CUBE_MAPもあります)。



テクスチャを付ける方法は?



着る前に、何を見つけてください。









1つの長方形(2つの三角形で構成される)はx0y平面にあり、その上に空のテクスチャを配置します。 これを行うには、OpenGLRendererクラスのprivate void prepareData()メソッドで、座標float []頂点の配列を作成します。ここで、三角形の座標だけでなく、対応するテクスチャの座標も入力します。



//coordinates for sky -2, 4, 0, 0, 0, -2, 0, 0, 0, 0.5f, 2, 4, 0, 0.5f, 0, 2, 0, 0, 0.5f, 0.5f,
      
      





ラインの最初の3つの数字は空の左上隅の座標(-2、4、0)で、次の2つの数字はテクセルポイントの座標(0,0)であり、これは三角形の頂点に対応します。 空の左下のエッジ(-2、0、0)と一致する2番目のポイント(2番目の行)に注意してください。テクセルポイントの座標(0、0.5f)、つまり s = 0(テクセルの左端)、およびt = 0.5。空のテクスチャはテクセルの半分だけを垂直方向に占有するためです。 次に、GL_TRIANGLE_STRIPメソッドを使用して3番目のポイント(空の右上端)と4番目のポイントを設定して2つの三角形を描画します(前のレッスンを参照)。



最初に2番目の平面(海)を最初の空(空)に垂直にすることを決めましたが、デバイスの正面の美しさのために、海の前端を少し下げて角度を少し増やしました。



 //coordinates for sea -2, 0, 0, 0.5f, 0, -2, -1, 2, 0.5f, 0.5f, 2, 0, 0, 1, 0, 2,-1, 2, 1, 0.5f,
      
      





アトラスから切り取った座標がどのように変化したかに注目してください。 イルカの画像を、空に平行な平面に配置し、0Z軸に沿って0.5単位だけシフトします。



 //coordinates for dolphin -1, 1, 0.5f, 0, 0.5f, -1, -1, 0.5f, 0, 1, 1, 1, 0.5f, 0.5f, 0.5f, 1, -1, 0.5f, 0.5f, 1,
      
      





イルカを別のイルカと交換したい場合は、ここで行う必要があります。 そのため、最初のステップを実行して、三角形の頂点とテクセルポイントを対応させました。



2番目のステップまたはテクスチャのロード方法



テクスチャのロードを説明する前に、テクスチャスロットなどの概念を扱う必要があります。 テクスチャーを接続するのは彼にとってであり、それを利用してさまざまな操作を実行し、パラメーターを変更できます。



次のように、作業用の現在のスロットを選択できます。



 GLES20.glActiveTexture(GLES20.GL_TEXTUREx);
      
      





ここで、GLES20.GL_TEXTURExは選択されたスロットの番号です(GLES20.GL_TEXTURE0など)。

定数は、32個のテクスチャ(最後のGL_TEXTURE31)に登録されます。



テクスチャをスロットに接続するには、次の手順を使用します



 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture_id);
      
      





ここで、最初のパラメータはテクスチャのタイプで、2番目はテクスチャへのリンクです。



このプロシージャは、GLES20.glActiveTexture()プロシージャによって以前に選択された現在のスロットにテクスチャをアタッチします。



つまり、特定のスロットにテクスチャをアタッチするには、2つのプロシージャを呼び出す必要があります。



 GLES20.glActiveTexture(_); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, __);
      
      





1つのテクスチャを複数のスロットに同時に接続することはできないことに注意してください。 別のスロットに切り替え、以前に接続されたスロットのテクスチャを設定しなかった場合、読み取りを試みると、アプリケーションがクラッシュする可能性が高くなります。



texture.pngグラフィックファイルをドローアブルプロジェクトリソースフォルダーに配置するとすぐに、システムは自動的にID番号を割り当てました(リソース識別子はこのリソースへのリンクである整数です)。 リソース識別子はR.javaファイルに保存されます。



TextureUtilsクラスにはloadTextureメソッドがあります。 このメソッドは、画像のリソースIDの入力を受け取り、出力は、この画像を含む作成されたテクスチャオブジェクトのIDを返します。



そのため、最初にグラフィックファイルのリソース識別子を引数として渡しますpublic static int loadTexture(Context context、int resourceId){



次に、1つの要素の空の配列を作成します。 この配列に、OpenGL ESはtextureIdsIdテクスチャ名と呼ばれる無料のテクスチャ番号を書き込みます。



 final int[] textureIds = new int[1];
      
      





次に、textureIds [0]に書き込まれる無料のテクスチャー名を生成します

glGenTextures(1、textureIds、0);



最初のパラメーターは、作成するテクスチャオブジェクトの数を決定します。 通常、作成するのは1つだけです。 次のパラメーターは、OpenGL ESが生成されたテクスチャオブジェクトのIDを書き込むテクスチャの名前です。 最後のパラメーターは、OpenGL ESに配列のどのポイントからIDの書き込みを開始するかを単に指示します。



何も書き込まれていないか確認し、ゼロを返します。



 if (textureIds[0] == 0) { return 0; }
      
      





inScaledフラグはデフォルトで有効になっており、スケーラブルでないバージョンのビットマップが必要な場合はオフにする必要があります。



 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false;
      
      





リソースからビットマップの画像をダウンロードする



 final Bitmap bitmap = BitmapFactory.decodeResource( context.getResources(), resourceId, options);
      
      





テクスチャオブジェクトはまだ空です。 これは、グラフィックデータがまだないことを意味します。 ビットマップをアップロードします。 これを行うには、最初にテクスチャをバインドする必要があります。 OpenGL ESでは、バインディングとは、バインディングを再度変更するまで、OpenGL ESが後続のすべての呼び出しにこの特定のオブジェクトを使用することを意味します。 この場合、オブジェクトのテクスチャをスナップします。 これを行うには、glBindTexture()メソッドを使用します。 テクスチャをアタッチすると、画像データなどのプロパティを制御できます。



アクティブなテクスチャスロットを選択します



 glActiveTexture(GL_TEXTURE0);
      
      





textureIds [0]という名前のテクスチャを現在のものにする



 glBindTexture(GL_TEXTURE_2D, textureIds[0]);
      
      





テクスチャの透明度を作成します。 これらの2行を書かないと、上のスクリーンショットのように、イルカは黒い不透明な背景になります。



 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); GLES20.glEnable(GLES20.GL_BLEND);
      
      





テクスチャオブジェクトを使用する前に、決定する必要があるもう1つの詳細があります。 これは、テクスチャの指定された領域にあるピクセルの数と比較して、三角形が画面上のピクセルをより多くまたはより少なく占有できるという事実によるものです。 たとえば、画面では、テクスチャゾーンから転送したピクセルよりもはるかに多くのピクセルを使用できます。 当然、逆の場合もあります。テクスチャの選択した領域よりも画面で使用するピクセルが少なくなります。 最初のケースは拡大と呼ばれ、2番目のケースは縮小です。 それぞれで、OpenGL ESにテクスチャの増減方法を指示する必要があります。 OpenGL ESの用語では、対応するメカニズムは縮小フィルターおよび拡大フィルターと呼ばれます。 これらのフィルターは、画像データ自体と同様に、テクスチャオブジェクトのプロパティです。 設定するには、まずglBindTexture()を使用してテクスチャオブジェクトがバインドされているかどうかを確認する必要があります。 その場合、次のようにインストールします。



 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
      
      





ここで画像に対するフィルターの効果について読むことができます



ビットマップをビデオカードメモリに書き換える



 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
      
      





次のように、メモリからビットマップを削除します 画像はすでにビデオメモリに書き換えられています



 bitmap.recycle();
      
      





最後に、0を渡すglBindTextureメソッドを再度呼び出します。テクスチャスロットGL_TEXTURE_2Dに、このスロットからテクスチャオブジェクトのリンクを解除します。



 glBindTexture(GL_TEXTURE_2D, 0); return textureIds[0];
      
      





もう一度、最初にGL_TEXTURE_2Dスロットにテクスチャオブジェクトを配置し、



 glBindTexture(GL_TEXTURE_2D, textureIds[0]);
      
      





その後、彼とのすべての操作を完了し、スロットを解放しました。 その結果、テクスチャオブジェクトがセットアップされ、作業の準備が整い、テクスチャスロットに関連付けられなくなりました。



シェーダーテクスチャアクセス



以前のレッスンでは、プログラムの本体に文字列オブジェクトとしてシェーダーを作成しました。 ここで提案されているように、それらを別のリソースに配置すると便利です 。 このようにして、resプロジェクトフォルダーにrawフォルダーが作成され、そこに2つのvertex_shader.glslおよびfragment_shader.glslファイルが配置されます。 ここにその内容があります



vertex_shader.glsl



 attribute vec4 a_Position; uniform mat4 u_Matrix; attribute vec2 a_Texture; varying vec2 v_Texture; void main() { gl_Position = u_Matrix * a_Position; v_Texture = a_Texture; }
      
      





ここでは、以前と同様に、マトリックスを使用して各頂点の最終座標(gl_Position)を計算します。 そして、属性a_Textureで、テクスチャの座標のデータを取得し、それをさまざまな変数v_Textureにすぐに書き込みます。 これにより、フラグメントシェーダーのテクスチャ座標で補間されたデータを取得できます。



fragment_shader.glsl



 precision mediump float; uniform sampler2D u_TextureUnit; varying vec2 v_Texture; void main() { gl_FragColor = texture2D(u_TextureUnit, v_Texture); }
      
      





まず、計算の平均精度を設定します



 precision mediump float;
      
      





GLSLには、sampler2Dと呼ばれる特別なタイプのユニフォームがあります。 サンプラーは、フラグメントシェーダーでのみ宣言できます。



 uniform sampler2D u_TextureUnit;
      
      





その中に、必要なテクスチャが配置されているテクスチャのスロット番号を取得する均一変数u_TextureUnitがあります。 変数のタイプに注意してください。 アプリケーションから整数としてこの変数に0を渡したことを思い出させてください。 つまり シェーダーに渡される数値(この場合は0)は、どのテクスチャスロットを見るかを示します。



可変v_Texture変数は、頂点シェーダーから補間されたテクスチャ座標を受け取ります。 また、シェーダーは、三角形の現在のポイントに表示するテクスチャポイントを認識しています。



テクスチャの座標とテクスチャ自体を使用して最終フラグメントを取得することは残ります。 これによりtexture2Dメソッドが実行され、gl_FragColorでテクスチャから目的のポイントの色を取得します。



ここからソースダウンロードしてください 。 幸運を祈ります!



主な情報源:

» Www.opengl.org/sdk/docs/

» Startandroid.ru

» Andmonahov.blogspot.com

» Developer.android.com/reference

» Www.opengl.org

» Www.learnopengles.com

" W3bsit3-dns.com/forum/lofiversion

» Developer.android.com/guide



All Articles