構造体アライメント

以前頂点データのサイズを少しでも減らすために頂点データ内にunsigned char等を使ったときに構造体のsizeof()で返ってくるデータサイズが自分の想像と違う時がありました。

全てfloatで宣言していた
struct VERTEX
{
float pos[3]; // 4*3
float normal[3]; // 4*3
float uv[2]; // 4*2
};

の時は問題無かったのですが、

float以外にshort intやcharを混ぜてもデータサイズが32のままで返ってきました。

この現象を色々と調べているとアライメントという単語に行き着いた・・・


・アライメントとはなんぞや?
メモリ上に変数が取られる時に、アドレスが決められた区切りによって
適当にメンバ間に空間を入れるらしいです。

これを構造体のアライメントというらしく、全く知らなかったのでなんで
勝手にデータサイズが変わってるんだと頭を抱えてました。

メモリコピーとかでモデルデータの構造体データを読み込んでコピーしようとしたら保存されてるデータとデータサイズが一致しなくて苦しみました。


この決められた間隔、区切りはコンパイラによって違うみたいなのですが、

#pragma命令によって変更できるようです。


恐らくデフォルトのアライメントは4バイトだと思われるので

#pragma pack(1)

などと書いた後に構造体を宣言すると上記の場合はアライメントサイズが1バイトになるようです。

宣言後は

#pragma pack() や #pragma pack(pop)

などで終わるのを忘れないようにしてください。



例:
#pragma pack(1)
struct VERTEX
{
short int pos[3]; // 2*3
short int normal[3]; // 2*3
unsigned char uv[2]; // 1*2
};
#pragma pack()

上記をpack(1)で囲まないと4バイトアライメントが入るので結局sizeof()
で取得したサイズはfloatで宣言したときのままの32バイトになってしまうはず。
例の通りだとsizeofで14が返ってくる。



構造体のメモリコピーやOpenGLでglVertexAttribPointer時のオフセットバイト数に注意していきたい。

OpenGLES高速化

たいした処理もしていないのに結構速度が出ない日々が続いていたので
色々と修正して速度の向上を図りました。


基本的にはネットで調べて大体の高速化を試してみた。


・よく書かれていたこと
 レンダリングステート系の重複処理を無くす。
 DrawElements系の描画メソッドの呼び出し回数を減らす。
 圧縮テクスチャを使用する(ビデオメモリ上にテクスチャを配置する)。


とりあえず上記3つを試してみた。

レンダリングステート系は管理クラスを作って変更があった時だけ切り替えるような物を作成。
DrawElements回数は2Dで大量に呼び出していたのでテクスチャ毎に頂点をまとめて一括表示する様な物を作成。

確かに速度は上がったが、何かがやっぱりおかしい
なんというか描画時に一瞬カクつく!!!

なんでだろうと更に調べていると、
頂点データサイズを減らすとデータの転送速度が上がるということでこれを試してみた。


従来の頂点データだと座標、法線、UV、頂点カラーなどを全てfloatで宣言していたのだが、これをなるべく軽いデータ

座標、法線を[short int]
UV、頂点カラーを[unsigned char]
にそれぞれ変更してみた。

1頂点あたりデータ量的には
float pos[3]; // 4*3
float normal[3]; // 4*3
float uv[2]; // 4*2

の32バイトだったのが、

short int pos[3]; // 2*3
short int normal[3]; // 2*3
unsigned char uv[2]; // 1*2

の14バイトに減った。


これがドンピシャで転送負荷が軽くなって描画時、バインド時にカクカクしてたのが改善されてスムーズに動く様に。


ただ浮動小数点を使わなくした分、データを変換する計算は増える。
UVの場合、0~255の値を0~1の範囲内にシェーダー上で変換してやらないといけない。

変換計算は頂点シェーダーの場合は命令負荷が比較的軽いので良いが、
これがピクセルシェーダーになると乗算1回でも悲鳴を上げたくなるほど激重になるので注意。

しかし相変わらず全体を覆うような物でアルファブレンドを使用するとめちゃくちゃ重い。こればかりはなんとかしてアルファブレンドを使用する物を減らすしか無さそうだ・・・

PVRTCのテクスチャコンバート

Apple系の開発リソースにはPVRTC形式のテクスチャがあるそうです。

これは圧縮されたテクスチャのフォーマットで描画の最適化に一役買ってくれそうな気がしたので使ってみました。

というか普通にpngのテクスチャをボカスカ使ってたら簡単に処理落ちしてしまったので色々と調べてたら行き着いたのがこれです。


コンバートの仕方や読み込みなどは
下記のページを参考にさせて頂きました。


・解説など詳しく読み込みのクラスも参考にさせて頂きました。
http://webos-goodies.jp/archives/using_compressed_textures_in_iphone.html


・コンバートの方法など参考にさせて頂きました。
http://ameblo.jp/xcc/entry-10298104084.html

http://d.hatena.ne.jp/nakamura001/20081229/1230557939


そしてXCode上でシェルスクリプトを実行してPVR形式の作成をコンパイルと同時に自動化してしまおうかなと思いスクリプト作成しました。

フォルダ内のpng形式の物を全てpvrコンバートするスクリプトを作成してみました。


TEXTURE_TOOL=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool
SRC_FILE=$SRCROOT/Data/Texture/PNG
DEST_FILE=$SRCROOT/Data/Texture/PVR

cd $SRC_FILE

#pngのテクスチャが見つかり続ける限りコンバートを行う
for i in *.png ;
do
	#拡張子変換
	echo $i
	ext_change=`echo $i | sed -e s/.png/.pvr/`

	#パスに変更
	SRC_FILE_NAME=$SRC_FILE/$i
	DEST_FILE_NAME=$DEST_FILE/$ext_change

	#pngファイルに更新があればコンバートを行う
	if test ! "$DEST_FILE_NAME" -nt "$SRC_FILE_NAME" ; then
		$TEXTURE_TOOL -m -e PVRTC --bits-per-pixel-4 -o "$DEST_FILE_NAME" -f PVR "$SRC_FILE_NAME"
	fi

done


上記使用する場合はフォルダパスなどを調整して下さい。


単純に元の画像から圧縮されたというのもありますが、
結果めちゃくちゃ起動が早くなりました。

ベクトル、行列演算

描画にOpenGLを使っているとベクトル演算系のメソッドが
一切無いのでこれらを自前で作らないといけません。

私は元々がDirectXを使って勉強したり、ゲームを作っていたので
D3DXVECTOR3とかD3DXVec3Transformなどがデフォルトであるので
それを使用しているだけでしたが、

いざ
OpenGLになるとこれらが無い・・・(私が知らないだけかもしれませんが


なのでベクトルとか行列のお勉強をしなおしたりしてる日々。

今となってはインターネット上にいろんな情報があったり、
既にこういったベクトル系の部分のソースがアップされていたりするのですが、
昔は全部本とか読んで勉強していたかと思うと凄く大変だと思う。


そんなとこでベクトル系のクラスとか作るのですが、
足し算、引き算は楽々進むんですが
内積外積やベクトルと行列の掛け算などになってくると計算の順番など間違えてないか物凄く不安になってきます。

ええ
案の定実行するとなんか違うなぁ〜と思うとxとyが逆になっていたりとかしたのですが


しかしまぁ
現在作っている物では使わなくても後々凄く重宝する部分なので
ベクトルの長さ求めるのとか色々と作成しました。


これでもうOpenGLもバッチこいな感じになると良いなぁ〜

OpenGLESで2Dを描く

色々触っていてそろそろ何か自分で画面に出してみようかなと思い
2D系の画像を出して見ることに


OpenGLDirectXと同じくプリミティブを表示するような関数があるので
そいつを使っていざ四角形を画面に出してみよう〜!


とやってみたわいいものの

glDrawElementsのGL_TRIANGLE_STRIPでは表示できるのに、
GL_TRIANGLESではなぜか画面に表示されない事態に陥りました。


理由は色々あったのですが(ほんと色々と知らないこといっぱいでs)

とりあえず
glDrawElementsの第一引数のプリミティブの書き方の指定が
OpenGLESだと普通のOpenGLよりもけっこう削られているらしく

参考にしようとした物とかもエラーになったりしました。

なので一番基本っぽい

TRIANGLESでなんとか画面に出るように試行錯誤・・・


普通に
glGenBuffersで作ったバッファオブジェクトに

頂点情報とインデックス情報を与えて描画しようとしたのですが、
これだと何も表示されない
もしくは三角形の欠けた状態しか画面に出ませんでした><

これはデータの切れ目を指定していなかったのが原因らしく

それを直すと上手くいきました。

指定は
glEnableVertexAttribArray( 番号 );
上記でAttributeの位置を決めて

glVertexAttribPointer( 番号, ....);
でその番号のデータオフセットなどを指定するようです。


これでバッファデータ分のオフセット値(頂点座標、UV座標、頂点カラー)を指定してあげて

再度glDrawElementsで描画!!!


しかしエラー落ちはなくなった物のまだなんか欠けてる・・・


こんな状態がDirectXの時もあったのですが、
今回も原因は同じで

インデックスバッファのインデックスの並び順が右回りになるように指定してあげないとOpenGLさんでも三角形が表示されないようです(当たり前かもしれませんが><)。


こんなチンぼけかましつつ
そこも修正したら見事に画面に四角形のポリゴンが無事に表示されましたwwひゃっほ〜い


ちょっとこの後はコイツを改造して色々とスプライトで遊んでみようかなと考えています。

XCodeでObjetive-CとC++を共有する

XCode上でプログラムを打っていて初めにぶち当たった壁でした。


XCodeでは基本的にObjective-Cの使用が推奨されているっぽいです。
ライブラリとか見てるとObjective-Cで書いてあるみたいですし・・・

でもC,C++が使えないかと言うとそんな事は無く普通に使用できます。
なので私は使い慣れたC,C++を使ってコードを書いていたんですが、


そこに落とし穴があった><


サンプルコード内に(.mなどで書かれたObjective-Cのソース)
自分で書いたC++系のソースをインクルードするとなぜか大量のエラーメッセージが・・・


なんか色々と調べていたら同じ問題になっている人も多いらしく
どうやらXCodeではファイルタイプによってコンパイル方法が変わっているっぽい。

なので複数のファイルタイプの物をコンパイルしようとするとおかしくなるようだ。


要は全部Objective-Cで書けば問題無いのだが、それだとクラス宣言周りとかC++から学んだ私にとっては全然違うのでかなり書きづらく感じる。

そこで解決方法としてはファイルのタイプを変更できるようだ。


XCode上の「グループとファイル」の一覧上にソースがたくさんあると思うけど、そこの自分で追加したソース(.cpp)などを右クリックすると「情報を見る」の項目があるはず!

これを選択するとファイルの情報が表示され、その中の「一般」タブ内に「ファイルタイプ」の項目がある。


これがcppでファイルを追加した場合に、デフォルトで「sourcecode.cpp.cpp」となっているようで
これを全て「sourcecode.cpp.objcpp」に変更するとエラーが全て解消された。

恐らく拡張子は違うが全てObjective-Cとしてコンパイルされているのか発生していたエラーが無くなりました。


ただ新しく追加する度に同じエラーが発生するので、その度に追加した
ファイルのファイルタイプを変更するのが少々めんどくさい。


これがどうにかならないもんかなぁ〜と考えています〜

iPhone開発

毎日プログラムばっかり打ってると色々と抜けていることも多そうなので日記を書いてみる事にしてみる。


とりあえずiPhoneのお仕事をする事になったので、全く解らない所を1から始めてみる。


まずiPhoneでアプリケーションを作るのに必要なもの。


これは既に前にやっていた人が居て、そのお古のマシンを使わせて頂く事になりました。


マシンはMac miniMacOSXです。
iPhoneの開発自体はMacがあれば基本的に無料で開発できるらしい。作ったアプリを売るとなると色々と登録しないといけないのと年間ライセンス料を払わないといけないらしいです。


そんなわけでMacとiPodTouch片手に始めるわけですが・・・


使うソフトはXCodeです。
これはVisualStdioとかCodeWarrierと同じ統合開発環境IDE)ですね。

たくさんプログラムを書いて
このソフトでビルドするとアプリケーション(.exe)が出来るって感じです。

よく使ってるVisualStdioと変わらず新規プロジェクトで自分の作りたいものに近いサンプルを選んで実行すればなんらか動くはず。

ただのビューを表示する物からopenGLESで描画処理を行うものまであります。


私は3DとかもやってみたかったのでOpenGLESのサンプルから初めてみました。(四角いボックスが上下に動くやつ)


まぁ初めて開発するので色々とわからないことだらけですが、ゆっくりやっていこうかと思いますが、作っていくうえで色々と日記に書いていけたらなぁ〜と思いまつ( ̄ー ̄)ノ