テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル


log

2010.03.17 C++:サウンドとテキストの実装

とりあえず早くフレームワーク部分の制作を終わらせて
実際のプレイ部分のコーディングに進みたかったので、
サクサクっとテキストスプライトとサウンドを導入してみました。
…という割には更新が若干遅れ気味ですが苦笑。

サウンドはDirectSoundで導入してみて、mmioを使用して
導入した関数とmmioを使用せずに導入した関数の2つを
一応用意してみたんですが、2つ試した感想としてはmmio関数を
使わない方が直感的な感じがしなくもないかな笑。

とりあえずこれで後は当たり判定をいれたら大体卒制と同じものが作れる
…と思ったんですが、そういえば肝心のアニメーションの
切り替えを実装し忘れてました。。

いかんいかん!モーション切り替えは早めに実装しようと思います。

2010.03.10 C++:シェーダスキンメッシュと少しDirectXに関する考察

ファイル 253-1.jpg

ようやくシェーダでスキンメッシュができるようになりました。
ようやく、ようやくですよ!長い道のりでした。

とりあえずCPUスキンメッシュとどのくらい処理速度が違うのか
計測してみましたが、早いです!やっぱりGPUは偉大だなと思いました。

以下少し比較めも&ちょっとした考察です。

・CPUスキンメッシュ(1/2モーションスキップ)、キャラ5体:50fps
・CPUスキンメッシュ(1/2モーションスキップ)、キャラ10体:28-30fps
・シェーダスキンメッシュ、キャラ5体:60fps
・シェーダスキンメッシュ、キャラ10体:53-55fps

今まで5体までしか表示してませんでしたが、試しに10体表示させてみると
やはり全然違ってきますね。それとパーティクルは現状、CPUで頂点計算
させているので、シェーダ有りでも10fpsほど落ちてしまうんですが、
これもシェーダで計算させるとまだ速度が上がるかもしれないです。

ただ、長い時間PCを使い続けているとなぜかCPUスキンメッシュと
シェーダスキンメッシュが同じくらいの速度(30fps近く)に
なってしまいました。PCを使い続けるとメモリが断片化して
処理効率が悪くなるのは前から気がついていたんですが、
シェーダ有り・無しとで速度が同じになるのは少し疑問だったりします。

そういえば、いままでDraw系命令を呼び出した直後に
GPUに描画命令が転送されているものだとばかり思ってましたが、
どうやらDraw系命令やSetRenderState系命令を行うと、
一度コマンドバッファと呼ばれるGPUでの命令手順を格納した
バッファにプッシュして、Present()を行うことでまとめて
命令とデータをGPUに転送しているんだそうです。なので
それによって実際はフレーム計算をしている間GPUは並行して
1つ前のフレームの描画を行ってるんだそうな。

てことは、以前考えていた「マルチスレッドにすることでGPGPUと
同じ理屈で処理が早くなるんじゃね?」というアイデアは意味がないですね。。
ただ、Lock()はその時点でGPUにアクセスしなければならないので
GPUがそのバッファを描画に利用していた場合、CPUは待機させられるそうです。

ということは!パーティクル計算が現在重いのはCPUで頂点計算を
させる際、待機させられているから処理が重くなっている可能性が高いので、
バッファを複数用意して、奇数フレーム用バッファと偶数フレーム用
バッファといった感じでバッファを使い分けることで、シェーダを使わずに
少しは処理速度が上がるんじゃないかなと、ふとそう思いました。

ただ、これだとバッファのための確保サイズが2倍になるので、
素直にシェーダでやっとけといわざる終えません!笑

2010.03.06 C++:スキンメッシュはシェーダでやるべし

最近は色々な実装を平行して作業したりしていて、片手間に
固定機能パイプラインのスキンメッシュを試してみたのですが、
色々と試行錯誤した点が多かったので以下めも。
(横文字がいつもより多くて非常に読みづらいので注意です!)

今までCPU計算でスキンメッシュさせていたやり方に
SetRenderState()のD3DRS_VERTEXBLENDフラグと
D3DRS_INDEXEDVERTEXBLENDENABLEフラグを使用して、
D3DTS_WORLDMATRIXに各フレームのスキニング行列を
設定してみると固定機能パイプラインで描画できるかなと考えたんですが。。
デバッグ中に、「あんさんのPCはD3DRS_INDEXEDVERTEX
BLENDENABLEをサポートしとらんよ」っていわれてしまいました。

そこでデバイス作成時のオプションをD3DCREATE_HARDWARE_
VERTEXPROCESSINGからD3DCREATE_SOFTWARE_
VERTEXPROCESSINGに変更してインデックスつきで
スキンメッシュ描画が無事できるようになったのですが…重い。
重すぎるのです。。キャラ1体表示させるだけでも20fps
程度しかでない、つまり自前CPU計算より何倍も重いんですよ。

後からWEBで色々と調べてみたところ、どうやらDirectX9系の
グラボはシェーダで描画することを推奨しているので、MaxVertex
BlendMatrixIndex(最大ブレンドマトリックスインデックス数)が
0のグラボが多いそうです。。なので、「スキンメッシュやるくらいなら
シェーダ使いんさい!」ってことらしいです。

DirectX9系以前のグラボの場合はD3DRS_INDEXEDVERTEX
BLENDENABLEフラグを使って固定機能パイプラインで描画したり
したほうが安定するんでしょうけど、対応させようにも自分の
環境だとデバッグすらできませんからね。。

今までネットでスキンメッシュについて調べていて、「なんで
みんな描画時に複雑な分岐フラグを立てて描画してるんだろう」と
思ってたんですが、ようやく分かったような気がしました。

とりあえずシェーダ対応ならシェーダで計算、シェーダ未対応なら
自前CPUで計算という形でプログラムを組んでいこうと思います。

2010.03.04 C++:デバッグひと段落

頑張った甲斐もあって、C++とDirectX両方のメモリリークエラーを
無事なくすことができました!ふう、疲れた。

そういえば、デバッグレベルを上げるとおそろしく処理が重くなりますね。
スプライトを数枚表示させるのでも30fpsしかでませんでしたよ。。
それと、メモリリークエラーを回避できた後に気づいたんですが、
メモリリークが発生してるとデバッグ時のプログラム終了が極端に
遅くなります。なので「なんだかデバッグの終了が遅いなあ」と
思ったらおそらく十中八九、メモリリークのチェックに時間が
かかってると考えていいのかなと思いました。

後はデバッグ中、デバッグウィンドウに山のように表示される
SetRenderState()等の警告を消すだけなのですが。
これってネットで調べてみると内部処理で同じ設定の場合は
スキップするようになっているようなので、自前でわざわざフラグを
たてる必要は本当はないらしいんですよね。。

けどじゃあなぜ警告がでるんだって話なんですが。。
とりあえずデバッグがとてもしづらいので自前のスキップ処理を
きちんとやっておこうと思います。

2010.03.03 C++:デバッグ茨道

今までデバッグについては、「とりあえずビルドが通ればそれでいいや」と
いった程度に考えていたんですが。_CrtSetDbgFlagを使って
メモリリークをチェックしてみると、かなりの数のメモリリークが
発生していることが分かりました。。

それでとりあえずDirectXのデバッグレベルを上げてチェックしてみると、
でてくるでてくる、エラーや警告の山!スプライトだけでチェックして
いるにも関わらず、エラーの数が多すぎて正直うんざりしてきます。

どうやらSetRenderState()を同じ設定で重複させても
警告がでるみたいで。本格的にデバッグをやろうと思うとかなり大変そうです。。

とりあえず、警告は無視してメモリリークだけエラーを回避すべきか。

2010.03.02 C++:パーティクル初歩

ファイル 249-1.jpg

パーティクルです!めらめら。

ここ最近はパーティクルシステムの作成にかかりきりでしたが、
とりあえず基本的な機能だけは無事実装させることができました。
しかし、パーティクルのソートがとにかく重いです。。現在は
バブルソートでソートしているのですが、30fps程度しかでなくなりました。

なので、実はパーティクルシステムと平行してこっそりと
SIMDの勉強をしていたりします。いまのところCPUばかり
酷使しすぎなんですが、あわよくばCPU・GPU共に
最大限機能を活かしたいところです。

今のところSIMDをサポートしているかチェックする部分だけ
搭載させているのですが、果たしてSIMDを使うところまでいけるかどうか。。
そもそも、僕のCPUだとSSE2までしか搭載していないし、
それ以上の命令を搭載させようにもデバッグすらできないという苦笑。

2010.02.24 C++:ストックバッファを作ってみました

今までやろうやろうといいつつやっていなかったアニメーションバッファの
ストック&再利用を試してみることにしました。
…はい、最近地味な作業ばかりが続いております。

とりあえずはじめはDirectXのバッファ型ではなく、自作の
頂点用構造体を利用して配列でバッファを作ってみたんですが。。
これがなぜか、45fps→40fpsと逆に速度が遅くなってしまったのです。

色々悩んだ末、ひょっとしたらD3DPOOL_SYSTEMMEMはただ
物理メモリに作成するのではなくて、GPUにアクセスしやすい
位置(?)に格納しているのではないかなと思い、今度は
DirectX本来のバッファ型で作成してみると、今までMAXで48fpsまでしか
でなかったのが、とりあえず50fpsまででるようになりました!
たかだか数fpsなんですが、50fpsまでいくと今までの地道な努力が
少しは報われたような気がします。当初はたったの20fpsでしたからね苦笑。

結論からいってしまうと、CPUで計算するかGPUで計算するかなんて
ほとんどどうでもいいくらい、CPU-GPU転送にかかる時間は
馬鹿でかいってことなんでしょうね。

それとストックバッファを利用してプログラムを数分起動していると、
なぜだかFPSが不安定になってプログラムのウィンドウが消えるという
症状が何度も発生してしまいました。おまけにVCもフリーズして
デバッグ結果が分からないという。。

おそらくはLock(),Unlock()を間髪入れずに何度も使用しているので
CPU-GPU間のアクセスでエラーが発生したのではないかなと
思うんですが、とりあえず原因はこれから調べるところです。

今まで、「こんな部分でエラーなんてでないだろ」と思って、
エラーチェックを外している部分が多かったんですが。。
ここに来てツケが回ってきやがりました。急がば回れ、と。

それと、色々と調べているうちに固定パイプラインでのスキンメッシュの
描画方法がなんとなく分かってきたので、これも近いうちに試してみて、
上手くいった場合はストックバッファなんて変な実装をやらずに
固定パイプラインで描画しようと思います笑。

2010.02.22 C++:ビープでカッコウ

最近はプログラムを少しずつ改良しておりました。
オブジェクトの開放処理を自動化させたり、マルチビューを搭載したり。

DirectSoundで音を搭載させようと考えているのですが、
色々難しそうだったので。色々調べ物をしてるうちにシステムの
ビープ音が鳴らせるようになりました。

それで、ビープ音で曲が作れないかなと思い、「かっこー」を
ビープ音で再生してみました。以下かっこー再生部分↓

Beep(1220,200); // かっ
Sleep(300);
Beep(980,500); // こー

WAVをビープ再生するソフトを作ってみても面白いかもしれない。
かなり近所迷惑になりそうですが苦笑。

2010.02.19 C++:DirectXプログレッシブメッシュ

現在サウンドを読み込めるようにプログラムを追加中です。

それで、ふとプログレッシブメッシュってどうやるんだろうと思ったので
調べてみると、どうやらID3DXMESHを使っている場合、
SetNumFaces()とSetNumVertices()で描画する面数と頂点数を
設定できるみたいですね。リダクションについては、元の形に
近くなるようにDirectXAPIで自動的に削除する面・ポイントを
選択してくれるようで。すごくお手軽です。

けど、スキンメッシュは自作クラスで実装したのでID3DXMESHは
使ってないんです。。まあ、動かないオブジェクトを
標準関数で読み込んでLODさせることなら出来そうですが、
標準関数の読み込みは座標が自動補正されるから気が引けます。。

なんとか自前実装できないかなあ。
頂点ごとの近接リストを別に用意して、それを元にLOD処理させたら、
フレーム毎の近接判定は出来ないけど結構高速にできそうな気がします。
というかそれくらいしか高速にLOD処理をさせる方法が思いつかないので、
SetNumFaces()とSetNumVertices()もそのやり方をとっていそう。

2010.02.15 LW:主人公途中経過

ファイル 245-1.jpg

スクリプトばっかりやってると飽きてきたので、今回はキャラクターの
制作に取り掛かってみました。主人公の男の子なんですが、
公式イラストをみると装飾が多い…。。ポリゴンとテクスチャが
予想以上に嵩んでしまいました。難しいなあ。

そうそう。スクリプトはLScriptとXSIスクリプトを平行して
勉強しているのですが、手軽さからいえばXSIスクリプトの方が上ですね。
LScriptは処理によっては不必要な手続きを踏まないと
いけなかったりするので、少し面倒だなあと感じました。

それとFBXのコンバータ、一応うまくいくことが分かりましたが。
よく分からない点もあったので、以下少しメモ。
・LW→XSIの際、複数のマテリアルでひとつのUVマップを
 併用していると、自動的にマテリアル数分UVマップがコピーされる。
・XSI→LWの際、メッシュオブジェクトはLWの座標系に
 自動的に変換されるが、チェイン・NullはXSIの座標系のまま。。
・XSI→LWの際、なぜかUVが吐き出されない。

チェインが変換されないのは、どう考えてもLWのインポートが
おかしいからだとして、UVが吐き出されないのはLWの問題なのか
XSIの問題なのか、よく分かりませんでした。ためしにXSIで
FBXをエクスポートして、それをXSIでインポートしてもUVが
読み込めなかったんですよね。…どういうこと?