スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

学校2週間は少なくともないのかな

同じ塾におります友人に聞いたところ、どうやらM大はゴールデンウィークあけまで休みらしいですね。
その上その人は成績表ももらっていないため一か月間生殺し状態らしいです。
ちなみにうちはどうなってるんですかね。今一つ具体性のある情報が少ないのだけれども。
見た感じ4/11にガイダンス日って感じなのでしょうか。誰か知ってたらメールしろ。して下さい。

あと最近白い画面見てると目が痛くなってくるのでブログの色を茶色くしてみた。
目が痛くなるほど見てたことないですけどね。VC++のエディタはデフォは白いのだよ。
背景色変えればいいんだろうが、初期設定大好き人間だからあんまりそういう変数弄りたくない。

あと全然見てなかった西さんのブログを開いたらやばい感じになってた。

すっごいピンク色だった。
一瞬なんかの宣伝サイトかと思った。
思わず肩に手をかけ首を横に振りたくなる感じだった。


「もう…手遅れだったんだ…」


ところで全然関係ないけれどもソースコードをHTML上で自動で色付けしてくれるプラグインを発見した。
せっかくだからテストも込めてWaveファイルの読み出しでも書いておこうか。

//読み込みバッファ
char data[4] ={0};

//ファイルを開く
std::ifstream ifs(m_FileName.c_str(), std::ios::in | std::ios::binary);
if(!ifs.is_open())
throw std::runtime_error("ファイルを開くのに失敗しました:"+m_FileName);

//RIFFタグ読み込み
const char RIFF[4] ={'R','I','F','F'};
ifs.read(data,sizeof(data));
if(memcmp(data, RIFF, sizeof(RIFF)) !=0)
throw std::runtime_error("RIFFファイルではありません:"+m_FileName);

//ファイルサイズは使わないので読み飛ばし
ifs.ignore(4);

//WAVEタグ読み込み
const char WAVE[4] ={'W','A','V','E'};
ifs.read(data,sizeof(data));
if(memcmp(data, WAVE, sizeof(WAVE)) !=0)
throw std::runtime_error("WAVEファイルではありません:"+m_FileName);

//FMT_タグ読み込み
const char FMT_[4] ={'f','m','t',' '};
ifs.read(data,sizeof(data));
if(memcmp(data, FMT_, sizeof(FMT_)) !=0)
throw std::runtime_error("フォーマットが取得できません:"+m_FileName);
//フォーマットサイズ読み取り
unsigned int fmtsize =0;
ifs.read((char*)&fmtsize,sizeof(fmtsize));
//フォーマット読み取り
ifs.read((char*)&m_wfx,16);
//拡張情報読み飛ばし
ifs.ignore(fmtsize-16);

//次のタグ読み込み
const char FACT[4] ={'f','a','c','t'};
const char DATA[4] ={'d','a','t','a'};
ifs.read(data,sizeof(data));
if(memcmp(data, FACT, sizeof(FACT)) ==0)
{
//factがあるときは適当に読み飛ばす
unsigned int factsize;
ifs.read((char*)&factsize,sizeof(factsize));
ifs.ignore(factsize);
}
else if(memcmp(data, DATA, sizeof(DATA)) !=0)
{
throw std::runtime_error("データが取得できません:"+m_FileName);
}

//波形データのサイズ読み取り
ifs.read((char*)&m_DataSize,sizeof(m_DataSize));

//データ部分までのオフセット値の取得
m_OffsetToData =(unsigned int)ifs.tellg();

いつかのとおりC++の標準ファイル操作関数でやってみた。動いてるから問題なかろう。
結局のところ、WAVEフォーマットてのは先頭にどんくらい入ってんの?っていう情報を書いた
無圧縮の波形バイナリデータがごぁーっと並んでるだけなので、あとはこのままゴリゴリバイナリで取ればいい。
ちなみにXAudio2についてはたぶんDirectSoundよりも格段に楽になっていると思う。
やった感じひたすらバイナリで取ってきて、キューすればいいから。
DirectSoundの場合だと、専用のバッファを作成しなければならなかったりしたのでめんどくさい。
と、いうことで誰かわかりやすく日本語で説明してくれる人が増えることを願って普及活動をしよう。
誰かより具体的な使い方を教えてください。


さて、今日一日調べた結果、前回言ったような多量の板ポリゴンをまとめて描画する仕組みは
スプライトバッチと呼ばれるもののようだ。バッチは同様の処理を繰り返すとかいった意味らしい。
マイクロソフトが箱○とWindows世に提供しているゲーム開発ライブラリであるXNAのヘルプを見ると、
デフォでSpriteBatchなるクラスが実装されているからたぶん有名な技術なのであろう。
で、それには基本となるメソッドとしてBegin(),Draw(),End()の三つが用意されている。
Begin()にて、描画ステートおよびバッチされるスプライト情報のプライオリティー設定がなされ、
Draw()にて、描画位置及びスケール、回転角度情報、適応するテクスチャがキューに入る。
この時点では実際には描画されているわけではなく、描画情報を累積しているよう。
そして最後に呼ばれるEnd()で実際に今までたまった情報をもとにすべてを書き出しているようなのだが、
ここでプライオリティー設定というのがこれらの描画順序を設定しているようだ。
同一テクスチャごと、深度設定ごと、並び替えなしすぐ描写、並び替えなしまとめて描写、
てな感じでいろいろ設定できるみたい。
中身でどうやって書いてるのかわからんが、頂点バッファには何を置いてるんだろうか?
いちいちロックしてるのか、行列送りつけてるのか。ただ行列送りつけるだとこの前言ったように
同一の変換しかしてくれないからやっぱり中身では頂点バッファに頂点情報を送ってるんだろうけど。
とすると、最低回転行列だけだけど、行列計算を頂点ごとにCPU側でやっているんだろうか。
となるとあんまりGPU側の計算が発生しないからDirectXの意味がなくなるってことでもないのだろうか。
わからん。

ということで同一テクスチャの同一オブジェクトをドバっとGPU側で演算できないものかと考えた。
おそらくこれはインスタンシングというものだろう。ハードウェア的にこれを実装している場合も
あるみたいだが、おそらくうちのパソコンはそんなに高性能じゃないので適応させるなら、
シェーダ側でやるシェーダインスタンシングというやつだろう。
ただ、たぶんこれは低頂点数の3Dオブジェクトをいっぱい作るときに向けての技術だろうから、
たった4頂点の板ポリに適応しても効果のほどがあるのかわからないけど。

一応概要的には、最低でも256個あるGPUの定数レジスタに各オブジェクトごとの情報を
設定しておいて、GPUに数値計算させようぜ、ってことな感じらしい。
特に深いこと、例えば動的に色を指定したりテクスチャ座標ずらしたり…、をしない場合、
一つの塊の姿勢制御に必要な最低限の情報は4*4の行列に凝縮できるから、
こいつを定数レジスタに登録してから、DrawPrimitiveを呼ぶというのが流れ。
この場合同一の頂点を反復使用できない(ハードインスタンシングではそうやるみたい)ので、
あらかじめ描画個数分だけ頂点バッファに頂点情報を確保しておくことになるようだ。
で、各頂点には登録された行列のうちどの行列で計算するのか、というインデクスを埋め込んでおく。
こうすることによって、GPU内でO(1)の速さで目的の行列を参照し、それぞれに任意の計算ができるわけだ。
ただし、定数レジスタの最低限保証されている個数は上に書いた通り256個なので、
4*4の行列だと一つにつき4つのレジスタいるから単純計算で64個(4次元ベクトルを1つのレジスタで保持できる)、
さらに現実的には少なくともView/Projectionの両行列演算はGPUに行わせるべきだから、
こいつらは定数値として保持しているとして大体60個程度が一度に描画できる限界になってくる。
シューティングの場合、最低限テクスチャの個数だけDrawPrimitiveは必要だとしても、
オブジェクトの個数が2000、3000はざらだろうし、これまた単純計算で300から500回程度の
呼び出しは必要ということになる。

が、MSDNとかを見る限り「1フレームにDrawほにゃらら系を2000回以上やったらクソだ。
さらに一回で最低でも1000ポリゴン描け。これは命令だ。」と書いてあるので、
300回程度ならたぶん許容範囲だろう。


ということで今回分かったことのまとめと、だれも興味のない今後の方針。

・スプライトはまとめて描画すべきSpriteBatchクラスを作成する。
→テクスチャおよび指定深度での並び替えに対応するのがたぶんいいと思うが、
 ソート自体の時間も考慮して、いろいろ考えよう。
・内部動作としてはバッファ全書き込みとインスタンシングの動作比較してから考える。
→なるべく外側からは何やってるのかわからないように。
・そろそろ頂点・ピクセルシェーダでも勉強。
→DirectX9の固定機能みたいなのと同じようなことをするのは比較的簡単だと理解した。
 +GPU側で単純な数値計算を並列処理させるというのはウェーイ。

たぶん出来合いのものを使ったほうが性能はいいし早いんだけど、
別に性能と速さではなくその過程…という名の「暇つぶし」が目的なので非効率どんと来い。


スポンサーサイト

Comment

コメントの投稿

Comment
管理者にだけ表示を許可する
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。