スポンサーサイト

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

C++とDirectX弄りの備忘録(2)

ということで2。今回はDirectInputの話。
ゲームにしろなんにしろユーザーからの入力は必要、ということで入力デバイスを一手に担ってくれるのが、
DirectXのなかでもDirectInputということになる。実際のところ使い方は割と簡単。

問題は、このAPIバージョン8からさっぱりアップデートがないこと。MSによると、

「DirectInputはもうやめた。ゲームパッドに関してはこれからはXInputを使え。
ただし対応しているのは箱のコントローラだけだ(笑。マウスとキーボードがほしけりゃWindowsのAPI使え」

つまるところ箱のコントローラを使わない限りは、WindowsのAPIを直接たたくかほかの手段を探すってことになる。
ゲームパッドに関してはそれ専用の取得APIがあるみたいで、めんどくさいが使えなくはない。
キーボードとマウスはAPIを使うとなると、GetAsyncKeyState()だったりGetCursorPos()あたりを使うか、
プロシージャのコールバックを利用しての実装をしろ、という意味なんだと思う。

どちらにしても割と仕込むのが面倒くさいので、やっぱりDirectInputを使うか、
箱(もしくは互換のある)コントローラを使うことを強要する、というくらいしか選択肢がないから
結局DirectInput使ったほうが楽っていうのが現状…なのでしょうか?
よくわからないからもっとほかの使いやすいライブラリがあったら教えてほしい。



ところでスプライトバッチの方は、ソートとかはめんどくさいのでとりあえずは、
指示された描画が同一テクスチャである限りはこれをバッファに貯め、
End()メソッドかテクスチャが変更されたときに動的頂点バッファに書き込んで
DrawIndexedPrimitive()する、って形だとリリースビルド時・最適化最大・最小限のコードで、
同一テクスチャだと7000枚程度の板ポリゴンであればぎりぎり60fpsを維持できるような感じにはなった。
ただ、単純計算28000頂点を処理したところで限界が来ているから、まだあまり効率がいいってわけではないか。
ちょっとまじめなゲームだったら数万頂点あるのは当たり前だろうしねぇ。
実際にはあたり判定だとかテクスチャの変更は起こるわけだから、まだまだ遅くなる。
ついでにUSAGEにDYNAMICを指定して頂点バッファを作成しているからか、
メモリの確保場所をPOOL_DEFAULTに設定しないとうまく頂点バッファが確保されない。
インデックスバッファは静的でいいから大丈夫なんだが、動的に操作するような場合は
POOL_DEFAULTフラグを設定しないとうまくいかないようだ。毎フレーム書き換えるからDYNAMIC指定したが、
もしかしたらWRITE_ONLYフラグだけのときと変わらないのかもしれない。おまじないおまじない。
これの問題は、デバイスロスト時にリソースのバックアップが行われないため再作成の必要があること。
まぁ7に変えてから未だかつてデバイスロストにあったことがない(XPは割とすぐなった)ので、
デバイスロストしたらご愁傷様でした、でももういい気がしてる。

あと効率化するとすれば、頂点情報に回転とスケール情報を埋め込んでGPU側に各々頂点計算をさせるか。
やはりそうなると頂点シェーダが必要になってくるし、例えば画面全体に適当なスクリーンをかぶせて色調を
ある程度統一させるといったエフェクトをやるならば、効率的にはピクセルシェーダを使わなければならない。

ここらでDirectX10or11に行ってみるか。いったん何かしらまとまったものを作ってから。
奴らはプログラマブルシェーダ必須だからいろいろ弄れるだろうし、用意されたスプライトクラスも
DirectX9のころとは違って即時描画じゃなくて一応そこそこのバッチ処理をしてくれるようになっているっぽい。
ついでにどうやらうちのPCはPS,VSともに3.0以上っぽいのでだいたいのことは試せるみたい。
ストリームソースを2つ使って、片方を反復して使用するような設定にしてやれば
(名前から察するにたぶんSetStreamSourceFreqだろうか)ハードウェアインスタンシングも可能か。



さて、DirectInputの使い方。ほかのDirectX系と同じく、
基本となるDirectInputインタフェースの作成→使用する各デバイス管理インタフェースの作成、
という具合でやってやればだいたい大丈夫っぽい。

ところでLinaxとかだと外部の入力装置ってってどうやって取得するんですかね。
たぶん直接、割と低レベルでの操作しないといけないからわけわからんのでしょうな。

続きを読む

スポンサーサイト

C++とDirectX弄りの備忘録(1)

中途半端に暇だということが判明した。言い換えると、5日だと思ってた猶予は2週間ある。
そしてりテイクを繰り返した結果ソースコードが膨大になりすぎて管理ができない。
ので自分の脳内整理を含めて一つづつ情報を残しておくことにした。
書けば覚える、書かなきゃ覚えない。バグが出てもあきらめない。
効率がいい、これこっちの方がいいんじゃね、ってのがあったら教えてください。

1.名前空間
今回適当にやってみてわかったのは意外と名前衝突は起こる可能性が高いということ。
これを回避する方法、および同一目的の関数群やグローバル定数などをパッキングする目的として、
C++には名前空間が存在する。よってこれを自作のクラスおよび関数には設定することにした。
また、テストを目的とするなどでない限り、標準ライブラリの名前空間stdに関して
usingディレクテブ・宣言を使用してはならない。
ある程度のブロックが限定された中での使用は、場合によっては冗長になるためやむを得ないが、
グローバルエリアでのこれは、その後にインクルードされたすべてのヘッダおよびソースで
有効になってしまうという関係上絶対にやってはならない。


2.コンストラクタとデストラクタ
コンストラクタでは失敗を通知する方法として、戻り値が存在しない以上例外を利用するしかない。
もしくはis_succeedみたいなメソッドを設けて作成後に成否を見るというのもあるが。
どちらにせよコンストラクタには、例外の発生があるものとして使用を心掛ける。
しかしnewおよびmallocで確保されたメモリに関しては、これらをもれなく解放しなければならない。
基本的にWindowsの環境下であれば、プロセス終了とともに割り当てられたすべてのリソースは解放されるため、
終了時にはメモリリークが起こっていても問題はないが、定期的に生成されるオブジェクトにおいて、
これが発生することはリソースを食いつぶすことにつながりシステムの安定性を低下させる。
また、ゲーム機とかPICとかみたいに組み込み向けに作るならリークした時点でまずいと思う。

よってこれを回避するためにデストラクタを用いる。
デストラクタが呼ばれる条件は、オブジェクトがスコープから外れるときおよびdelete式であるが、
前者を利用してnewで確保したメモリのポインタに関しての管理を別オブジェクトに移譲する。
例えばstd::auto_ptrとか。C++にはJavaみたいに例外仕様にfinallyが存在しないため、
なるべくヒープから確保したメモリに関しては、そいつらのデストラクタと道連れに死んでもらう。
だからなるべくnewで確保した生ポインタを使用せず、scoped_aryだったりsmart_ptrを使う。
これによって、上位のクラスほどデストラクタでの解放処理を書く必要がなくなる。

続きを読む

描画の効率化

さて描画入力音声と、3拍子揃ったので実際どんくらい速度でるのか試した。

1000個程度矩形を書いたところでfpsが急に落ちた。全然駄目やないか。
あれ、ちょっと前にやったときには5000個位までいけたのに。

で、どうやらボトルネックは
・やっぱりdrawprimitive呼びすぎ
・やっぱりテクスチャ切り替えすぎ
ってことらしい。よくわからんが。

そもそも3Dみたいにひとつのオブジェクトが何千何万頂点あるのと違い、
平面の場合は4頂点~を基本としているわけで土台が違うわけだ。
となると、drawprimitiveやsettextureみたいによびだしコストが高い奴はやばいわけだ。
今はなんも考えず一枚書くのにテクスチャセットからdrawprimitiveをしてるわけだが、
これはまとめられる限りまとめた方がもちろんいいと。
が、2Dだと大概の場合は基本頂点情報はおなじで位置だけ違うってのが多いから、
適応する変換行列を複数選択できない以上、変換行列で頂点操作するには個数分drawprimitiveがいる。
頂点ブレンドを本来使われるべく用意された方法無視して使えば、出来ないことはないがぶっちゃけ無駄だろう。
恐らくはインデクス付三角形リストを毎描画一度だけロックして書き込み、がいいか。
のためには、描画をしたいクライアントは最低限の情報を描画担当者に次々渡し、
最後まで来たらまとめてロックし描画をするという仕組みだろうか。
他に適するものとしてdrawprimitiveupというのもあるが、directX10以降オミットされたので非推奨なんだろうか。
きっと中身では渡された頂点配列GPUに送りつけてるわけだから、やってることは同じってこと?誰か教えて。
しかし動的配列となるとやっぱベクターか。STLまじぱねぇ。ついでにboostもぱねぇ。早くC++0xこい。
もうなんか普通の配列とか使うけどいらないよ。
ただこれやると、システムメモリに数千の頂点配列を確保することになるが…。
まいいか。今回はメモリをふんだんに無駄使いしよう!の方針で行こう。
さてこの場合、テクスチャ切り替えを減らすには、テクスチャ別に描画出来る機構が必要となる。
ついでに同じテクスチャグループは、一画像内にいくつかテクスチャを小分けして設置して、考慮する事になる。
と、こんどはクライアント側でテクスチャ座標を考慮する事になる。
するとどうだ、面倒くさいので、一元管理したくなる。
時間がなくなる。
ウボァー。


見事な連携だな。
だが無意味だ。


一通りふざけたところで話を戻すと、結局どちらにしても描画依頼側は描画情報を出さなければならないが何が必要か。
最低限頂点位置、まずはこれは必要だろう。しかし自由変形や五角形以上を描かない限り、
描画位置を示すのに四角形に必要なのは、中心と幅・高さでいい。
逆に任意個数頂点に対応したものにするには可変長配列が必要となるが、newが発生する…
のは微妙なので、根源の三角形と長方形の2種類あればどんな形もいけると信じよう。
三角形だと重複頂点があるがもう知らん。連続性フラグとか設けて、ダブりをなるべく無くそう。
基本は長方形とすると、後必要なのは頂点色とテクスチャ座標。
頂点色はガリガリ好きに書いて貰うとして、件のテクスチャ座標は、
何かテクスチャ名とかかいて貰うことで、ファイルとテクスチャ座標を気にしなくていい機構を考えよう。
あるいは動的に実行時そんなふうに並んだテクスチャが作れると嬉しいんだけどね。
既存のテクスチャをマージする方法とかあるんでしょうかね。

そろそろ学校

始まるけど始まるのかね。ぶっちゃけ電車が地獄になる未来しか見えない。
もう自身自体で地獄なんだけどね。本棚の立てつけが悪くて私の部屋の本棚が倒れて崩壊してる。
もはや直す気も起きないほどに残念なことになっている。俺の漫画があああああ。
大体登校時間とか授業中に停電したらどうするんだろうね。あそこ停電区域か知らんけど。
ただ実験とかほんと涙目になるよね。それともそれなりに予備電源とか用意されてんだろうか。
まあ停電がどうとか言いつつ未だに一回も来ないですけどね。地区的にはバリバリ直球なわけだが。

そんなことよりマジ西さん悪運強い。
何がすごいって和歌山にいること(たぶん)。もう今の世の中和歌山にいること自体がステータス。
西の方には京都大阪とあるが中でも和歌山。もう和歌山のみかんは世界中を救うに違いない。
ぱないの。

塾は地震の日に「無事でしょうか。情報が錯綜しておりますが状況が安定し次第連絡をします」、
なニュアンスのメールが来たわけだが、あれから一切連絡がない。
そろそろ一週間経つんだけどそれはつまり安定していないという日本語なんだろうか。
さすがにつぶれたとかは無しにしてほしい。後味が悪い。



ところで話は変わりますが、なんだかんだでやっと最近片付けが終わって、
パソコン弄る余裕が出てきたのでXAudio2を使ってWAVEファイルを再生する枠組みを作りました。
OggVorbisとかmp3とかも、とくにOggの方はやろうとすればやれるんだけどめんどくさいからやってない。
それでですね、思うにプログラムの何がめんどくさいかっていうと、それは初期化だと思うの。
ということで2行書くだけで再生開始できるようにしました。

AudioPtr audio =CreateAudio("test.wav",STREAMING);
audio->Start();

みたいな感じで。ただしもちろん若干の効率低下には目をつぶって。個人的にはもう満足です。

できることは

・ストリーミング再生
・全読み込み再生
・全読み込みで複数の同じ音を同時再生
・ボリューム上げ下げ
・ピッチ上げ下げ

補助を使うことによって線形的な

・フェードイン
・フェードアウト

という感じとなりました。
エフェクトもつけられるみたいだけどそんなに興味がないのでスルー。
ピッチ上げ下げしながら聞くと、「こぉんなぁものかぁ」とか「コンナモノカッ」みたいになって面白い。
問題は頭出し。デフォルトで渡したデータをストリーミングしてしまうからよくわからん。
今のところもっとも簡単に思いつくのは、たぶん作り直すこと。
キューを捨てることができれば何とかなるんだけどね。
誰かソースボイスのキューを取り去る方法を教えてください。

追記:
と思ったらものの30秒後にFlushSourceBuffersというメソッドを発見。
そうかFlushか…いままでデリートとか消去とかで目星つけてたから見つからなかったのか…

newキーワードとnew演算子

あんこおおおぉぉ!
いい娘だったのに…。


見返したらタイトルが文字化けしていることを発見。墨灼◆鏡か…。
西さんが好きそうだな。元からタイトルなんか意味あること書いてないからどうでもいいや。

さらにずいぶん前から微妙にコメントが付いていたことを今更確認。
そして若干真面目にC++のこととか書くと、全く反応がないことも確認。なんだよ。
>スカイプに音声じゃないがUPっといた。
見に行ったが何もなかった。っていうかそもそも最近の会話がなかった。

そしてめっきり格ゲーの腕は上達しない。無理だろ指の動き的な意味で。
でもアマ公がかわいいから許す。フェリシアはウザいから帰れ。
使いやすさでいうとスーパースクラルが個人的に使いやすい。技も出しやすいし。
ただし欠点は、なんか知らないけどデザインが噛ませキャラを彷彿させる。なんでだろ…。
噂によると相変わらず前作から続いてセンチネル祭りらしいがそれは少しでも格ゲーが
「できる」判定の人だけだろうと思う。初心者があいつで出征するとあたり判定でかいからウワアアアア。


さて、Nの字も関係なくなってきたNISHIGE、塾のせいでさっぱり進まないがWave解析クラスは作成できた。
基本的なC++のファイルストリームでの実装だからなんとなくWindows依存ではなくなるだろう。
さてこっからはストリーミングスレッドとかの、スレッドを管理するクラスを作るべきか。
めんどくさいし今のと頃はbeginthreadexだか何かで直接作っちゃえばいいかな。
ただ今ひとつ子スレッドが終わるまでどういう風にどこ待つべきかよくわからない。
どっちにせよXAudio2の本体を管理するクラスと、効果音とかストリーミングしない音声、
BGM等ストリーミングしたい音声を再生するためのプレーヤークラスの3つの実装かな目標は。

で、それができたら前に作ったDirectInput用のクラスを改善すると。
そしたら描画・入力・音声がそろうのであとは本編を作ると。

まずは全体を管理する構成を考えて、システムを考える。シーンの移り変わりとか。
なるべく敵を作成したり自機を作成したりする動作を一元化して、使いやすくする。
そしてそれを管理できるようなリストを作る。…これはSTLのリストでもいいか。

ま、たぶん時間的に終わらないんですけどね。この休みじゃ。さてここから本題。オブジェクトを構成する先のメモリを指定(したり)するnew、
いわゆる配置newを調べて分かった、そもそもnewとはなんなのかの覚え書き。

まず、結論としてnewとoperator new、そしてdeleteとoperator deleteは、完全に別物だと言うこと。
いやー初めて知ったよ。なるほどとは思うが。だって巷の本に書いてないじゃない。
普通にメモリ確保に使ういわゆるnew・deleteは、newやnew演算子、new式などと呼ばれ、
オーバーロードできるnewもあまり区別されず、newやnew演算子、new演算子関数とか呼ばれてるっぽい。


今回は区別のため、前者をただのnew、後者をnew演算子と呼ぼう。
deleteも同じ感じで。以下間違えないように。


で、newとdeleteにはそれぞれ次の役目がある。(これらは、式として呼びだされたもののこと)

new
・オブジェクトを構成するメモリのポインタを返す
・コンストラクタの呼び出し
delete
・デストラクタの呼び出し
・指定ポインタのメモリの解放

見て分かるように、どちらも二段構えで処理が行われる(らしい。
さてここで、コンストラクタ・デストラクタの呼び出しを、
new・delete演算子オーバーロードではしていない事実がある。
つまりnew・delete演算子はメモリの確保と解放処理のみをすげ替えているわけ。
これらをオーバーロードすると、ただのnewに引数を指定できて、
それらを使って独自に作る場所を返すように変えてもいいよってことらしい。
new演算子はどこに作るか、という情報を最低限返せばいいため、
必ずしもヒープからメモリ確保を行う必要性は無いみたい。
だからこそplacement newが可能らしい。デフォルトはmalloc()辺りで確保してるみたい。


そうすると、必然deleteとdelete演算子はどうなのってことになる。
これはnewとは事情が異なってくる。なぜなら、delete演算子をオーバーロードしても、
それらの引数をdeleteに渡せる構文がC++言語に無いから。
じゃあどこで呼ばれんのってことだが、これはオーバーロードしたnew演算子で
オブジェクト確保をしてかつ、その後のコンストラクタで例外が投げられたとき、
というめちゃくちゃ限定的な状態らしい。今のところ出会ったことないよ。それじゃどうやってdeleteするのか、ってことなんだが、placement newに関しては、
もとより確保してるメモリに配置しているので、呼ぶ必要はない。
ただ、オブジェクト内でさらにメモリ確保してた時なんかはデストラクタ呼びたいので、
直接デストラクタを呼ぶってのが解決法のひとつみたいである。
もしくは、そのオブジェクトの動的確保がplacement newでしか行われないとするなら、
空実装のdelete演算子を定義してやることで、実質メモリ解放処理をせず、
デストラクタを呼び出すだけの処理になるみたい。
ここで適当なこと書いてやれば自分で確保してるメモリを返してもらえそうですな。

ということを頭に入れて残りの休みC++を弄りませうか。


テンプレート

C++ではテンプレートというものがつかえるので、そいつを使ってスマートポインタらしきものと
ウィークポインタらしきものを実装することができました。
方式は参照カウント方式で、参照カウントのメモリ確保は、あらかじめ確保しておいたところに
placement newすることによってやっているので多少は効率化できてたらいいなと思っている。
実際に時間は計測していないので、もしかしたらより効率悪くしてるかもしれないが。
まぁ変更自体は他ができちゃってからでも影響を与えずにできるのであとで考えよう。

さて、あとはこれでXAudio2という未知・不確定要素さえ攻略できれば、やっとゲームシステムを作ること
になるんでしょうな…。たどり着く気がしないけど、たどり着かなくても別にいいと思うと気が楽。
やはり趣味的なものってのは、死んでも誰かの頼みや仕事でやるもんじゃないな。

そうそう、ノベルはさ、すべては西さんにかかっている。そろそろ無理やり西さん西さんひたすら言うてる
モチベーションも続かなくなってくるころだから、ここらで西さんには大きな花火をあげてもらいたい。
おもに私たちが一時の楽しみと話題を得るために。きーみーのーオモイガー。
…西さんがボイスを自分で録音して送ってくれるとイッシーさんが一晩でやってくれると思うんだけど。
どうせ形はできてるし、あと必要なのは絵と声、つまり素材だけだ。ったような気がする。

それはそれで置いといて結局どうしませうかね…。
ここはやっぱり少しはちゃんと得点システムをつけたシューティングでリベンジするか。
基本のショットを2種類位作ってコンボでも作るとか。
後はそうだな、個人的幼き日触れたシューティングのロマン、ロックオンレーザーを。
色は適当に画面の統一感を出せるようにモノクロベースで。
別に画像を作るのがめんどくさいわけじゃない。
アルファ値つきの画像とかぶっちゃけめんどくさいだなんて思ってない。
これさえなければ10倍の速さで進むのになんて全然思ってない。

そう、GIMPというフリーソフトがあるのですがこれが知らないうちに進化してた。
いや前からあったのかもしれませんけど、色を透明度になる神がかった機能があることを発見。
しかもなんとデフォルトで日本語対応で、何となくUIも心なしかスタイリッシュになっている気が…。
とはいえ2年以上前から脳内情報を更新してなかったので何ともいえない。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。