OpenGL ES2 でテクスチャ 〜iOS版〜

久しぶりの投稿だわ。加えて久しぶりのプログラミングネタ、というより、なーんか苦労したんで忘れないようにメモ。
iOSプログラミングでOpenGL ES2 のテクスチャ関連を調べてみると意外と情報がまとまっていない。見つかったと思ったら、よくわからないのライブラリ使っていたり、コードが中途半端に抜けていたり、C++コードが混ざっていてそのままじゃ使えなかったりと、なんでこう使えないのが多いのかな?と思うほど。Android向けの方が結構まとまっている感がある。


iPhone 3GS からだったか、OpenGL ES2 が使えるようになったのは。困ったことにOpenGL ES1.xとは互換がないと言っていいほど違う。特に描画。ES2からシェーダなるものが導入され、これを使わないといけないらしい。ただ、シェーダもプログラミング言語で書かれるので、いろいろできそうではある。これは今後の課題かな。うまくいけば弾幕計算をGPGPUでやることも可能かと。シェーダの細かいことはおいといて、テクスチャうまくいったので、それを書いておく。シェーダはGLSLなる言語で書かれているらしい。


2DのゲームでOpenGLを使うとなると、作成した画像はテクスチャで貼ることになる。なので、テクスチャは結構肝なのだな。
さてさて、実際にコードを記していこう。
まず、Xcodeにて新規プロジェクトから・・・あれ?なんか画面かわってる・・・???あれ?作成されるテンプレートがES2オンリーになっている。ipod touch 2nd系のES1.xしか使えない端末(3Gもかな?)が切り捨てられたか。さすがApple
フルコードは作り直すとして、手順だけ書いておこう。


まずは、vertex shader。ここに、テクスチャに関する情報を設定する。といっても、座標とかはメインのプログラムから渡されてくるので、代入や演算処理だけになる。

attribute vec4 position;
attribute vec2 texcoord;
varying vec2 texcoordVarying;

void main()
{
    gl_Position = position;
    texcoordVarying = texcoord;
}

attribute で宣言したものはメインプログラムから渡ってくるもの、varying はfragment shaderに渡すもの、gl_PositionはOpenGL ES2ライブラリが内部的に持っている変数で、この変数に値を設定するとその場所に描画してくれる。今回は、描画位置positionと用意した画像に対するクリップ範囲texcoordをそのままセットする。


次にfragment shader。

precision mediump float;
varying vec2 texcoordVarying;
uniform sampler2D texture;

void main()
{
    gl_FragColor = texture2D(texture, texcoordVarying);
}        

precision で演算精度を決められるらしい。
varying で宣言されている texcoordVarying はvertex shaderから渡ってくる。
uniform で宣言された変数はメインプログラムとやり取りできる。なのでtextureもメインプログラムから渡ってくる。変数の型(vec2 とか vec4とか sampler2Dとか)は割愛。調べてね。
gl_FragColorは表示物の色用変数で、gl_Positionと同様に、OpenGLライブラリが内部的に持っている変数のようです。この変数に表示色を設定します。今回はテクスチャで画像表示が目的なので、texture2D()を使って、テクスチャの色をそのまま出すように設定しています。


いよいよ、メインのプログラムです。
まず変数定義しておきましょう。列挙型です。これは、シェーダの変数にアクセスする(値を渡す)ために必要です。あ、なくてもできますが、可読性が悪くなります。

// Uniform index.
enum {
    UNIFORM_TEXTURE,
    NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];

// Attribute index.
enum {
    ATTRIB_VERTEX,
    ATTRIB_TEXCOORD,
    NUM_ATTRIBUTES
};

シェーダでuniformで宣言された変数に対するものと、attributeで宣言された変数に対するものですね。
どうやら、メインプログラムからシェーダ変数へはIDのような数値でアクセするようで、しかもそのIDは宣言順に0, 1, 2・・・と割り当てられているようですね。


次に初期化。OpenGLの初期化のところに(ビューの初期化時でも良いと思う)、以下を追加します。

glEnableVertexAttribArray(ATTRIB_VERTEX);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glEnable(GL_TEXTURE_2D);

mTexture = [self loadTexture:@"back.png"];
    
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

vertexとtexcoordを使えるようにglEnableVertexAttribArray()をしておきます。テクスチャを使うので、ATTRIB_TEXCOORDを忘れないように。また、テクスチャを使うので、glEnable()でGL_TEXTURE_2Dを使用可能にしておきます。
次にテクスチャを作成して(loadTextureは自分で用意する。これはOpenGL ES1.xでも同じ)、ブレンドするので、ブレンドの設定をしておきます。今回は余意味がありませんが。。。


次は、シェーダのロード。テクスチャを使うためにシェーダないで使用するattributeの変数を変更しているので、メインプログラムに対応関係を教える必要があります。今回、VERTEX<->position、TEXCOORD<->texcoordなので、lglLinkProgram()の前あたりに

glBindAttribLocation(program, ATTRIB_VERTEX, "position");
glBindAttribLocation(program, ATTRIB_TEXCOORD, "texcoord" );

をしておきます。

最後に、実際の描画です。
以前のテンプレートだと drawFrameメソッドの中身・・・ですが、まぁ、適宜合わせてください。
vertex、texcoordの座標を設定してそれらをシェーダに渡します。
とりあえずサンプルなので決めうちで設定してシェーダに渡します。

float vertexs[] = {
    -1.0f, -1.0f, 0.0f,  //left top
    -1.0f,  1.0f, 0.0f,   //left bottom
      1.0f, -1.0f, 0.0f,   //right top
      1.0f,  1.0f, 0.0f,   //right bottom
};

float texcoords[] = {
    0.0f, 0.0f,//left top
    0.0f, 1.0f,//left bottom
    1.0f, 0.0f,//right top
    1.0f, 1.0f,//right bottom
};

glUseProgram(program);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture);
glUniform1i(uniforms[UNIFORM_TEXTURE], 0);

glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, false, 0, texcoords);                
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, false, 0, vertexs);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

テクスチャは複数用意できるのでglActiveTexture()でアクティブにするテクスチャを選択できます。今回は1つなのでテクスチャ0をアクティブに。
glBindTexture()で作成したテクスチャを渡します。
glUniform1i()でシェーダにuniformで宣言した変数に値を渡します。今回はtextureの値ですね。
glVertexAttribPointer()でattributeで宣言した変数に値を渡します。vertexとtexcoordですね。
最後に glDrawArrays()で描画となります。


ところで、今回は1画像を貼付けただけなので、これで良いのですが、弾幕シューティングのようにたくさんの弾が出てきたらどうするんでしょう。弾の種類分テクスチャを用意してテクスチャを切り替えて弾の数だけ glDrawArray()して表示・・・なんてやってたら、重くてゲームになりません。最近の端末なら多少いけるかもしれませんが、少なくとも ipod touch 2ndでは全然だめでした。そもそもglDrawArrays()は描画処理なので結構重いです。なので、これを減らす工夫が必要になります。glDrawArrays()を1回にする方法がありますが、それはまた、まとまってからということで。ES1.1のがそのままいければすぐにまとまると思いますが。。。
今回はここまで。


あー、そうそう、Androidも同じような感じでできるので、できたらメモるかも。

au光の1G

うちのネット環境au光の1Gなんだけど、500Mどころか、100Mも出てない。あ、正確には1PCからの通信テストが70M前後の結果になる。TVサービスも使ってるので実際は合計で数百は出ていると思うんだけどね。
ちなみに、複数のP2Pをフル稼働させてみたら・・・TV止まったww。
値がでないのはホームゲートウェイ(HW)が原因だろうと思って調べてみた。HWはAterm BL190HWって製品らしく、一応G対応しているみたいだ。


じゃぁなんでだ・・・・
HWの設定を見ていったらLAN側Ethernet設定欄があって、[10Mbps/全・半二重][100Mbps/全・半二重][自動]となっている。
ん?これが原因か?ひょっとして。ポートとしては1Gまで対応しているようだが、どうもソフト的に対応してないように見えるんだが。自動で100Mオーバー出るようになっているように思えないのは気のせいか。
まぁ、不自由はしていないからいいか。

Intel GPUの処理落ち原因判明?

あけましておめでとう。今年も気ままに・・・


さてさてさて、前回東方が処理落ちするのはGPUでなかろうか?と書いたが、ちょいと調べてみた。
GPU-Zなるソフトで現在のクロックが見られるらしいので、妖精大戦争やりながら観察してみた。
おかげでクリアできませんでしたが・・・よそ見してできるゲームじゃぁねぇな。


GPUのくロックを観察してみたら一応追従してクロック数は上がっているみたいだ。が、
どうも追従するのが遅いようだ。
ゲーム起動後200MHz付近で安定する。弾幕大量生成時に一応クロック数が増えるがワンテンポ遅い気がする。これが原因ではなかろうか。
負荷がかかるのは短いので、クロックの変動がついて行けないと、カクついたり処理落ちしたりする。ん〜仕方がないのかなぁ。
なんとか、ベースクロックをあげた状態で東方やりたいのだけれども、BIOSいじりたくないしねぇ。IntelGPUのツール誰か作ってくれないかなぁ・・・

Intel graphics hdも・・・?

Core i5 (Mobileむけ)のノートPCに東方を入れて遊んでみたら、すこぶる処理落ちするのだけど。。。
特に妖精大戦争は酷い。地霊殿も微妙に怪しいところが少しあるねぇ。
うちの前のデスクトップ(Core2Duoの初期 + Radion HD 5670のクロックを300-400MHzにセット)で快適に動くので
CPUが問題とも思えない。おそらくGPU側と思われる。
で、調べてみるとGPUCore i5内蔵のIntel Graphics HDとわかる。こいつの性能が悪いのか???とおもったんだけど、
こっちも調べてみたら、悪くても 166-500MHz なので、性能的には問題ないはず。
つーことは、クロックがあがってないんじゃないかと思われる。
AMDのときにも書いたが、どうやら2Dで負荷をかけてもあまりクロックがあがらないようだ。実際にはかってみないとわからないが・・・
AMDNVIDIAはツールがあるので良いのだけどなぁ。
Intel Graphics向けツールが欲しいところだ。。。
ちなみに OS は Win7 64bit。どーもハード的な問題?それともDirectXか?
何れにしてもなんとかならんもんかね〜

R1 東方キャラでパズルゲーム

ずーっと忙しくて放置気味だった。久しぶりの投稿だわ


さてさて、かなり前に東方キャラでパズルゲームが水面下で進行中と書いたけども、実現しました。スナップショットはこんな感じ(あ、面制作画面になってた)。

PCだったら、みるくあいらんどで遊べます。
Java appletなので、パスワード方式ですが・・・
あ、イメージセットいろいろあるので、最初は画面が違うから。


Android版もあります。Android端末持っている人は入れてみてはいかがでしょうか。
あいにく私はAndroid端末を持っていないので。
iPhone版は鋭意??製作中。
あ、実際に作ったのは、
みるくあいらんど管理人+絵師+面制作数人のチーム。
私は面作成に関わった人です。


果たして何人の人が全クリできるのか・・・

iPhoneで弾幕風っぽいもの作成中 -dylibが埋め込めない-

長期で休暇もらったんで、久しぶりに、iPhoneプログラミングをやっているんだけども、なかなかはかどらないねぇ。
で、東方必技禄を発展させて、弾幕風っぽいものにしようと考えてるんだけども、dynamic libraryがなかなかうまくできない。
iOSでdynamic libraryで作ることはできるんだが、どうもdylibファイルをアプリに埋め込めない。これができないと、弾幕風ができても、サンプルを埋め込むことができない。困ったなぁ。


dylibをリソースに含めようとして、プロジェクトに追加すると、アプリ起動時にエラーが出る。ロードできないって言われて。。。dlopen使わなくてもこのエラーが出るので、どうやら、dylib自体を登録できないようだ。やりかたあるのかなぁ。。。
で、拡張しかえてみたが・・・駄目!どうやってもリソースに含まれてくれない。


とりあえず、dylibは使えそうなので(appleの審査が通るかは不明だけど)もうちょっと模索してみようかな。


ちなみに・・・iOSでdynamic libraryではObjective-Cを使ったdylibは作れません。Objective-Cのクラスを使う場合は -framework Foundation 等のオプションがいります。

Mac OSX Lion 所感

わりと前にアップデートをしてLionを使ってみてるんだが、いくらかバグがあるような気がする。
致命的になのはMacbook airにてスリープから復帰したときにマウスが中途半端に固まる点。
いやね、カーソルは動くんですよ。ええ。クリックが効かなくなるだけで。
ショートカット知らないから困ったねぇ。今度調べとこかな。
結局電源ボタン押して終了させて、再起動させたんだが、なんかいい方法ないかねぇ。


次にいただけないのはFlashのバグ。FireFoxのバグといってる人もいるみたいだけど、
うちのmacminiではsafariでもおこるので、どうやらLionでのflashのバグと見ていいのではないだろうか。
バグの内容は mac版firefox3-6でニコニコ動画が見られない (URLに日本語が入ると駄目だねこれ)に詳しくあるが、flashのダイアログが出るんだが、なぜかクリックが効かず何もできないという現象。このダイアログが邪魔して動画が見れないのだ。早くなんとかしてほしい。


最後に、LaunchPad。使い物にならん。ほとんど編集できないのと一緒なので。
アップデート時に入っていたアプリは自動的に登録されるらしい。その上消せないのはなぜ??
さらに、そこにあるアプリをアップデートしたら、同じものなのに2つ登録されているのはなんで???
使えんすぎる。
ちなみに、3rdパーティでLaunchpad controlなるものがあって、編集できるようになるらしいのだが、
1ヶ月近く?サイトにつながらないんだが。。。
ていうか、3rdパーティに頼らないといけないようなもん作るなよな。まったく。
だいたい、新しいもの導入した後必ずたたかれるよね。中途半端なんだよな。調査が足りないんだよ。
spacesのときもそうだったし。
早く改善してほしいものだ。