AndroidでのGLSLは困ったことに、コンパイル時にこけても、エラーログを吐きません。
デスクトップでコンパイルのテストして、持っていくという手段をとってますが、それでもコンパイルが通らなかったりします。
以下微妙にはまった点を。
フラグメントシェーダでは精度を指定する
変数はlowp, mediump, highpを指定しないといけません。ちなみにhighpはExtensionらしいです。
型チェックが厳しい
定数に1を指定したら、コンパイル時にこけました。Int型と判断されたためでしょう。変数がfloatの場合、1.0とfloatの定数を指定する必要があります。
これどうやって見つけたかというと、最小構成のシェーダにした後、じょじょに範囲を広げていって、こけている行を特定しました。
IDEのビジュアルデバッガを使っていると、こういう初歩的なデバッグテクニックを忘れがちになりますね。気をつけないと。
2011年6月20日月曜日
2011年6月16日木曜日
AndroidでOpenGL ES 2.0を学びたい
Androidでゲームを作りたい人なのでGLES20を学んでいます。
OpenGLの知識は1.1で止ったままなので、もはや別物と化してしまったGLES20は改めて学ぶ必要があるようです。
まず、GLES20のAPIを学ぶ上で罠っぽいところが結構ありまして…
ならこまめにOnOff切り替えればいいじゃないかと思われる方もいらっしゃるでしょうが、パフォーマンス上の理由であまりお勧めできません。
GPUへの命令発行は可能な限り減らさなければならないのです。
問題は2です。慣れてないと非常に気持ち悪いです。例えばテクスチャアドレッシングモードを変更する(glTexParameteri)とき、対象となるテクスチャをバインド(glBindTexture)しないと変更できません。テクスチャネームを指定して直接変更…できたらいいんですけど、できません。
もうひとつ例を挙げると、Shaderに渡すAttribute変数を設定する関数(glVertexAttribPointer)があるのですが、この関数、VBOがバインドされている場合とそうでない場合では渡す引数の意味が変わります。通常はデータへのポインタを渡すのですが、VBOがバインドされている場合、VBOのオフセットを渡す必要があります。このあたり理解して無いと…それは後述します。
3はまぁ、時代の流れですね。固定シェーダがやってたことと同じシェーダを書くことはそんなに難しいものではないので、特に問題はないと思います。
あと、Androidの開発言語はJavaなわけですが、Javaオンリーで開発すると罠がいくつかあります。
もうひとつ、OpenGLにはデータチャンクを渡すAPIがあるのですが、これが大抵引数がjava.nio.Bufferなんです。それだけならまだ救いがあるのですが、DirectBufferかつNativeOrderという条件が加わります。
悪いことに、DirectBufferが必要となると、まずByteBufferが必要になるのですが、asXXXBuffer()による変換後のオブジェクトは、array()メソッドがサポートされていません。putで書き込む必要があります。
すなわち、頂点データを加工するには、Javaだと二倍のメモリ(そしてコピーのコスト)を払う必要があるわけです。かといって、メモリをけちって1要素ずつput()したら動作速度は目も当てられないことにになります。
2はもう、あからさまに回りくどいです。手順としては
なのでNDKを使わざるを得ないのが実情かと。
追記:
Bitmapを直接読み込めるAPIありました…android.opengl.GLUtilsがそれです。
2.3が出回れば、JavaのみでOpenGLを問題なく叩けそうですね。
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を問題なく叩けそうですね。
登録:
投稿 (Atom)