OpenGLの知識は1.1で止ったままなので、もはや別物と化してしまったGLES20は改めて学ぶ必要があるようです。
まず、GLES20のAPIを学ぶ上で罠っぽいところが結構ありまして…
- OpenGLはステートを内部に溜め込む
- ステートによって関数の意味が変わる
- 固定シェーダが無くなった
ならこまめにOnOff切り替えればいいじゃないかと思われる方もいらっしゃるでしょうが、パフォーマンス上の理由であまりお勧めできません。
GPUへの命令発行は可能な限り減らさなければならないのです。
問題は2です。慣れてないと非常に気持ち悪いです。例えばテクスチャアドレッシングモードを変更する(glTexParameteri)とき、対象となるテクスチャをバインド(glBindTexture)しないと変更できません。テクスチャネームを指定して直接変更…できたらいいんですけど、できません。
もうひとつ例を挙げると、Shaderに渡すAttribute変数を設定する関数(glVertexAttribPointer)があるのですが、この関数、VBOがバインドされている場合とそうでない場合では渡す引数の意味が変わります。通常はデータへのポインタを渡すのですが、VBOがバインドされている場合、VBOのオフセットを渡す必要があります。このあたり理解して無いと…それは後述します。
3はまぁ、時代の流れですね。固定シェーダがやってたことと同じシェーダを書くことはそんなに難しいものではないので、特に問題はないと思います。
あと、Androidの開発言語はJavaなわけですが、Javaオンリーで開発すると罠がいくつかあります。
- Android2.2のGLES20のAPI設計したヤツでてこい!><
- テクスチャ読み込みが回りくどい
もうひとつ、OpenGLにはデータチャンクを渡すAPIがあるのですが、これが大抵引数がjava.nio.Bufferなんです。それだけならまだ救いがあるのですが、DirectBufferかつNativeOrderという条件が加わります。
悪いことに、DirectBufferが必要となると、まずByteBufferが必要になるのですが、asXXXBuffer()による変換後のオブジェクトは、array()メソッドがサポートされていません。putで書き込む必要があります。
すなわち、頂点データを加工するには、Javaだと二倍のメモリ(そしてコピーのコスト)を払う必要があるわけです。かといって、メモリをけちって1要素ずつput()したら動作速度は目も当てられないことにになります。
2はもう、あからさまに回りくどいです。手順としては
- BitmapFactoryからリソースを読み込み、Bitmapを取得
- getPixels()でピクセル値を取得
- 色の並びをOpenGLに合わせる(Option)
- ネイティブオーダーかつダイレクトなByteBufferを作成(ByteBuffer.allocateDirect() ByteBuffer.order())する。
- ByteBufferにピクセル値を書き込む
- ビデオメモリに転送(glTexImage(), glTexSubImage())
- Bitmapを開放(recycle())
なのでNDKを使わざるを得ないのが実情かと。
追記:
Bitmapを直接読み込めるAPIありました…android.opengl.GLUtilsがそれです。
2.3が出回れば、JavaのみでOpenGLを問題なく叩けそうですね。
0 件のコメント:
コメントを投稿