ページ 11

格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月16日(金) 23:49
by コマンダーヤンマーク
はじめて投稿します。

格闘ゲームをC++とDXlibで作ろうとしていますが
なかなか問題が解決できないため投稿させて頂きました。

「現象」
だいたい格闘ゲームとして戦えるとこまでは組んだのですが
キャラ画像を描画するときにFPSが60から50くらいまで下がる減少が起きます。
格闘ゲームだとFPSはかなり重要なので必ず解決したい問題です・・・
下がるタイミングとしてはキャラクターが特定のモーションに変化したときに落ちます。
同キャラで戦わせてみましたが、1Pでは下がらなかったのに、2Pでは下がるモーションもあります。
一度行った行動は処理落ちしないようです。

「設計」
・解像度は1280*720で開発しており、キャラ画像はだいたい300*400ぐらいです。
・キャラ画像ファイルはアニメーションを横にずらっと並べたpngファイルで8bit、24色まで減色してあります。
 (モーションによってまちまちですが横サイズが8000を超えているものもあります)
・1キャラの全画像の合計容量は3.23MGでした。
・画像のロードはモーションごとに" LoadDivGraph "で読み込んでいます。
 読み込むタイミングはお互いのキャラ選択が終了したときに一度だけロード関数を呼び出しています。
・描画はDrawRotaGraph3をつかってブレンド、色調整できる関数描画を作り
 エフェクト、UIも含めて同じ関数で描画できるようにしていました。
・背景はありません。
・ロードをループに入れていることもないです。

「環境」
OS:windows7 Home Premium 64ビット
CPU:Intel Core i7-3820CPU@3.60GHz
メモリ:16384MG RAM
DirectXバージョン:DirectX11
チップの種類:GeForce GTX 560
メモリ合計:4050MG
メインドライバ:nnvd3dumx.dll,nvwgf2umx.dll,n
ドライババージョン:9.18.13.1106

VC++ 2010Express
DXlib 3.10e
ゲームパッド「SANWA JY-P69UW」2つ


「試してみたこと」
・エフェクト、UIの描画関数をすべてコメントアウト→効果なし
・SetDrawBright();やブレンドモードを変更すると重くなるらしいので、それ系の関数をすべてコメントアウト→効果なし
・バトル開始直前にすべてのモーションを高速で描画してみる→なぜか効果なし!?
・DrawRotaGraph3は重いらしいので早いと噂のDrawExtendGraphで描画→効果なし
・Releaseで実行→効果なし
・VRAMがなんかあやしいので" SetUseNotManageTextureFlag( FALSE ); "を試す→効果なし
・" SetUseVramFlag( TRUE ); "を行ってみる→効果なし
・" SetScreenMemToVramFlag( FALSE ); "を入れてみる→現象が変化!
 「特定のモーションでFPS低下」→「常にFPSは60~55でガタついているが、特定のモーションでは変化しない」
・↑コレなら" SetWaitVSyncFlag(FALSE); "で処理速度上がるからイケるかも!→FPSはあがったが結局ガッタガタ

☆FPSを保てた解決?方法

コード:

	SetWaitVSyncFlag(FALSE) ;
	SetUseVramFlag( TRUE ) ;
	SetScreenMemToVramFlag( FALSE ) ;
	if( DxLib_Init() == -1 ) return -1;
	SetUseNotManageTextureFlag( FALSE ) ;
の状態にしてエフェクト、UIの描画関数をコメントアウトしたところ
FPSが60.3~59.9を保つようになりました。(画面ガタガタしますが)

長くなりましたが以上です。

画像ファイルが大きすぎなのでしょうか?
ロード方法に問題があるのでしょうか?

よろしくお願いいたします。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 00:24
by ISLe
コマンダーヤンマーク さんが書きました:・キャラ画像ファイルはアニメーションを横にずらっと並べたpngファイルで8bit、24色まで減色してあります。
 (モーションによってまちまちですが横サイズが8000を超えているものもあります)
・1キャラの全画像の合計容量は3.23MGでした。
この数値は画像ファイルのサイズですか?
実行時に消費する容量はVRAM上でのピクセルサイズで計算する必要がありますが。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 00:44
by コマンダーヤンマーク
返信ありがとうございます。
「横サイズ」っていうのはピクセルです。
「合計容量」は1キャラ1カラーの全画像ファイルが入ったフォルダのプロパティから見た合計サイズです。(すみません3.23MBの書き間違えです)

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 10:03
by softya(ソフト屋)
ファイル上のサイズとVRAM上のサイズは異なるよって話をISLeさんはされている訳です。
実際にはもっと大きくなります。特にDXLIBは特殊なことしていた様な。
ちと計算の仕方は調べてきます。

【補足】
NVidia系のビデオカードを利用中ならnvidiaInspectorと言うツールでVRAMの利用量を動的に確認可能です。
※ 何の画像がxxMBとか細かいかとは分かりませんが。

【追記】
新しい画像の表示でメインRAM→VRAMの転送で遅延している気がするので、全グラフィックを一度表示させれば安定するんじゃないと言う気がしました。
ゲームの対戦が始まる前に画面をフェードアウトしといて一気に全部描画できませんか?

SetWaitVSyncFlag(FALSE) ; ← 止めたほうが良いです。
SetUseVramFlag( TRUE ) ;
SetScreenMemToVramFlag( FALSE ) ; ← 止めたほうが良いです。
if( DxLib_Init() == -1 ) return -1;
SetUseNotManageTextureFlag( FALSE ) ; ← これは微妙かも。どちらか良いかは試してみてください。

【補足の追記】
VRAM容量以前に、【追記】で書いたことをまず確認お願いします。
これで解決するんじゃないかと思っております。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 11:29
by タミア
画像サイズを2の乗数(512,1024など)にすると改善するかもしれません。
自分も似たような状況になったことがありますが、それで改善しました。

また、画像のロードに関してですが、LoadDivGraphだと
画像に無駄な部分(例えばキャラの立ち状態時は縦長で、
 ダウン時は横長なので両方が入るサイズで分割にするとそれぞれで大きな余白ができる)
ができてしまうので、DerivationGraphをつかったほうがいいかもしれません。
問題とは直接関係ないかもしれませんが、画像サイズを少しでも減らせると思います。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 15:40
by aguroq
► スポイラーを表示
勝手に他の人の質問を解決にしようとしたフォーラムルール違反です。 by softya(ソフト屋) 

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 18:13
by ISLe
容量不足なら、全部表示しても、VRAMから追い出されたテクスチャを再度表示しようとしたときに遅延が発生するのではないでしょうか。

SetUseNotManageTextureFlag(FALSE);
テクスチャ管理機能が働かないので、VRAMに入らないテクスチャは常にシステムメモリ上にあるか作成に失敗するはずです。
常に特定のテクスチャで遅延が発生することになります。

SetScreenMemToVramFlag(FALSE);
そもそもハードウェアアクセラレーションが働かなくなるので、テクスチャ管理も何もVRAMが関係なくなります。
描画機能がすべてCPUで行われるので高いCPU性能が求められることになります。


DXライブラリは内部でテクスチャを2の累乗サイズに分割するそうです。
テクスチャサイズをあらかじめ2の累乗サイズにしておくと、テクスチャ管理において複数のテクスチャが同時に扱われることを避けられる点で有効だと思われます。

SetUseDivGraphFlag(FALSE);
でDXライブラリが内部でテクスチャを分割するのを抑制できますが、テクスチャの消費するメモリ量が増える可能性があります。

テクスチャサイズをあらかじめ2の累乗サイズにすることは、動作速度とメモリ消費量の効率アップの両立になります。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 18:27
by コマンダーヤンマーク
ありがとうございます。
タミア さんが書きました:画像サイズを2の乗数(512,1024など)にすると改善するかもしれません。
softya(ソフト屋) さんが書きました: 新しい画像の表示でメインRAM→VRAMの転送で遅延している気がするので、全グラフィックを一度表示させれば安定するんじゃないと言う気がしました。
ゲームの対戦が始まる前に画面をフェードアウトしといて一気に全部描画できませんか?

SetWaitVSyncFlag(FALSE) ; ← 止めたほうが良いです。
SetUseVramFlag( TRUE ) ;
SetScreenMemToVramFlag( FALSE ) ; ← 止めたほうが良いです。
if( DxLib_Init() == -1 ) return -1;
SetUseNotManageTextureFlag( FALSE ) ; ← これは微妙かも。どちらか良いかは試してみてください。
一度これらのことを試してみます。
softya(ソフト屋)さん、ロードした全キャラグラフィックを描画するのはこんな感じでよいでしょうか?

コード:

for(int i=0;i<2;i++){							//1Pと2P分おこなう
	for(int j=0;j<ACTION_TYPE;j++){				//モーションの最大数だけ行う
		if(graphic.Player[i][j][0]==0)break;	//モーションの先頭GHが何も無ければ抜ける
		for(int k=0;k<ANIME_NUM_MAX;k++){		//モーションのアニメーションの最大枚数だけ行う
			if(graphic.Player[i][j][k]==0)break;//GHが何も無ければ抜ける
			DrawGraph(0,0,graphic.Player[i][j][k],TRUE);//キャラ描画
		}
	}
}
//"graphic.Player[i][j][k] "はグラフィックハンドルです。
バトル開始前にこれで描画してみたのですが、効果はありませんでした。
それとも一枚ずつ描画して数フレーム間待つとか
そういったことは必要でしょうか?
VRAMの仕組みはイマイチわかっていないのでスミマセン(--;)

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 18:35
by softya(ソフト屋)
>softya(ソフト屋)さん、ロードした全キャラグラフィックを描画するのはこんな感じでよいでしょうか?

こんな感じです。
これで効果が無いのなら、VRAMをオーバーしているのかもしれませんね。
あと、お持ちのPCのスペックが書いていないので、そもそも無謀なのかもしれません。
ちなみに市販の格闘ゲーム系だとVRAMに収め得るためにパーツごとに分解したり、かなり省メモリの工夫をしてあるはずです。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 19:12
by コマンダーヤンマーク
今画像サイズを2の累乗に変更している作業中です。
softya(ソフト屋) さんが書きました: あと、お持ちのPCのスペックが書いていないので、そもそも無謀なのかもしれません。
無謀・・・!マジですか・・・
まだまだ描画しなければいけない背景やエフェクトもあるのに
キャラ描画でスペック不足だとがっくりしますねぇ・・・
一応ビデオメモリが4050MBあるので
高解像度の開発もいけるかなと踏んだのですが・・・

とりあえず2の累乗を試してまた報告します!

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 19:18
by softya(ソフト屋)
4GBですか?それなら十分というか開発したゲームを配布するなら、もっと容量少なめで考えておかないとやばそうですね。
もっとノートとかVRAMとメインRAMが兼用のメモリに厳しいPCかと思っていました。
ところで、上に書いたnvidiaInspectorは試されました?

【補足】
最初にGeForce GTX 560と書かれてましたね。
失礼しました。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 19:57
by だんごさん
質問文ともにざっとしか見てないので違うかもしれませんが、 SetDrawScreen( DX_SCREEN_BACK ) で実行していないではないですか?

もし上記の関数で裏画面処理をしていないのであれば、「13a. 裏画面処理をして画像を動かす。」を参考にプログラムを書いてみてください。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 20:07
by コマンダーヤンマーク
softya(ソフト屋) さんが書きました:4GBですか?それなら十分というか開発したゲームを配布するなら、もっと容量少なめで考えておかないとやばそうですね。
もっとノートとかVRAMとメインRAMが兼用のメモリに厳しいPCかと思っていました。
ところで、上に書いたnvidiaInspectorは試されました?
すみません。今試してみました。
ビデオメモリは正しくは1GBでした・・・
共有システムメモリ3GBを合計したものをみていました。すみません

nvidiaInspectorでの「今何MB使用している?」とういう確認方法がわからなかったため
GPUオブザーバーガジェットで確認したところ、見事にパンパンでした・・・。
2の累乗サイズにして軽減できるか試してみます (--;)
だんごさん さんが書きました:質問文ともにざっとしか見てないので違うかもしれませんが、 SetDrawScreen( DX_SCREEN_BACK ) で実行していないではないですか?
ありがとうございます。
SetDrawScreen( DX_SCREEN_BACK ) ;  は if( DxLib_Init() == -1 ) return -1;
の後に一度だけ実行しています。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 20:32
by だんごさん
コマンダーヤンマーク さんが書きました:ありがとうございます。
SetDrawScreen( DX_SCREEN_BACK ) ;  は if( DxLib_Init() == -1 ) return -1;
の後に一度だけ実行しています。
そうですか…。
一応聞きますが、ScreenFilp関数もループに1個だけ呼び出してますか?この関数が2個以上あるとバグやFPSの低下の原因になります。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 21:07
by コマンダーヤンマーク
だんごさん さんが書きました: 一応聞きますが、ScreenFilp関数もループに1個だけ呼び出してますか?この関数が2個以上あるとバグやFPSの低下の原因になります。

コード:

while(ProcessMessage() == 0 && GetHitKeyStateAll(Key) == 0){
ClearDrawScreen();
//-----------------------------------------------------------------------------------
//いじるのはココだけ
//スウィッチ文で各モード(タイトルやらキャラセレ)の関数を呼び出しています。
//-----------------------------------------------------------------------------------
ScreenFlip() ;
//ここらへんはFPS制御系など
}
という感じの設計なので重い処理の重複は無いと思われます。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 21:26
by softya(ソフト屋)
とりあえず、サイズ計算してみましょうか。
「使用画像データの限界(?)について質問」 ← 参考
http://hpcgi2.nifty.com/natupaji/bbs/pa ... ast&no=305
まずウィンドウモードで、画面バッファがダブルで表示バッファを合わせて1280*720*4byte*3ですかね?
これは約11MB程度で大したことないです。

と言うことで、問題はLoadDivGrpah()している方ということになります。
「画像読み込みと解放について」
http://hpcgi2.nifty.com/natupaji/bbs/pa ... st&no=2536
ここにVRAM上は1ピクセル4バイト使うと書いてありますので、
2P x ACTION_TYPE x ANIME_NUM_MAX x 画像サイズ x 4byte
で容量的に収まるかを計算してみてください。
画像サイズは 300*400みたいですが他の情報がないので計算がこちらでできません。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 22:26
by コマンダーヤンマーク
softya(ソフト屋) さんが書きました:とりあえず、サイズ計算してみましょうか。
「使用画像データの限界(?)について質問」 ← 参考
http://hpcgi2.nifty.com/natupaji/bbs/pa ... ast&no=305
まずウィンドウモードで、画面バッファがダブルで表示バッファを合わせて1280*720*4byte*3ですかね?
これは約11MB程度で大したことないです。

と言うことで、問題はLoadDivGrpah()している方ということになります。
「画像読み込みと解放について」
http://hpcgi2.nifty.com/natupaji/bbs/pa ... st&no=2536
ここにVRAM上は1ピクセル4バイト使うと書いてありますので、
2P x ACTION_TYPE x ANIME_NUM_MAX x 画像サイズ x 4byte
で容量的に収まるかを計算してみてください。
画像サイズは 300*400みたいですが他の情報がないので計算がこちらでできません。
おおお!ありがとうございます!
エクセルで管理していたので計算が楽でした!
計算方法はこの様な感じでしょうか?
LoadDivGraph( *FileName ,AllNum ,XNum ,YNum ,XSize , YSize , *HandleBuf ) ;
とすると
2P×SUM(AllNum×XSize×YSize×4byte)[モーション分の合計です]=?
という感じでしょうか。

結果は
643535952 byte=約614MB
でかいですね・・・。

ところで
http://hpcgi2.nifty.com/natupaji/bbs/pa ... st&no=2536
こちらのほうにかかれていることを
「同じ画像サイズだとメモリの使用が軽減」されるというニュアンスで捕らえたのですが
あっているでしょうか?
だとすると、私が作っていた画像ファイルはすべて元画像サイズ、読み込み画像サイズがバラバラでしたので
それも問題かもしれませんね・・・

※今さらですけど2の累乗が重要なのは「元画像サイズ」ですよね?
読み込み時の画像サイズ(XSize,YSize)は関係ないですよね?(↑に書いていることが合っていれば統一は必要そうですが・・・)

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 22:44
by softya(ソフト屋)
「VRAM上の画像にアクセスするための使いまわしようのシステムメモリ上の画像」は、メインRAM→VRAM転送を減らすための工夫なのでコマンダーヤンマーク さんの多量の大きな画像だと効果が無いと思います。計算上で約614MBですか。たしかに、それは足らなくなりそうですね。

DXライブラリやDirectXの内部動作が分からない所が有るので、表示する画像を1タイプづつ増やしてGPUオブザーバーガジェットの容量の変化でサイズを調べるという方法もあります。これなら実測値なので嘘はないです。

どっちにしても2の累乗とかの問題を片付けても論理値が614MBだと破綻の危険はつきまといそうですね。
画面モードを16bit カラーにすると半分に成るとの噂はありますが、今はどちらなのでしょうか?

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月17日(土) 23:07
by コマンダーヤンマーク
>DXライブラリやDirectXの内部動作が分からない所が有るので、表示する画像を1タイプづつ増やしてGPUオブザーバーガジェットの容量の変化でサイズを調べるという方法もあります。これなら実測値なので嘘はないです。

これなら何がどう問題なのかわかりやすそうですね。やってみます。

>どっちにしても2の累乗とかの問題を片付けても論理値が614MBだと破綻の危険はつきまといそうですね。

オウフ・・・。マジですか。しかもエフェクト、UI、背景を抜いての値ですから余裕で無理そうですね・・・。

>画面モードを16bit カラーにすると半分に成るとの噂はありますが、今はどちらなのでしょうか?

とりあえず32bitでやっています。ためしに
SetGraphMode(WINDOW_WIDTH ,WINDOW_HEIGHT , 16 );
で16bitモードにしてみましたが効果は無かったです。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月18日(日) 00:10
by コマンダーヤンマーク
大きなサイズの画像(特に処理落ちしてた画像など)をピックアップし、ロードしないようにして
全部のモーションをロードしたときのVRAM使用量と比べてみました。

☆何もロードせずに実行した場合の値は約114MBでした。
これを基本の値とします。

☆全部ロードした場合
基本値+計算値
114MB+614MB=728MB
実行値
987MB(FPS不安定)

☆大きいサイズの画像をロードしなかった場合
基本値+計算値
114MB+263MB=377MB
実行値
682MB(FPS安定)

※エフェクト、UI、背景はロードなし

計算と結構違うみたいです(考え方が合っているか分からないですが)
どうやってVRAMの使用量を抑えるかがポイントなんですかねぇ…
安直に画像を小さくしても
高解像度でキャラ画像が小さいと迫力ないので、難しいですねぇ…

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月18日(日) 00:21
by softya(ソフト屋)
やっぱりギリギリまで使うのは避けたいですね。
全部入れても最後の最後のいざと言う保険を残して80%ぐらいに留めたい所です。

サイズですが、512とか2の累乗サイズでない部分で無駄が出ているのかもしれません。
ただし、それで直るかは小規模な実験をしてみないとわかんないです。

あとは画像を減らすために、画像をパーツ化して同じ画像のパーツ部分をデータとして持たないようにするかですね。
専用のツールを作る手間とか、絵を見直すとか相当な手間が必要です。

それか画像を微妙に縮小して、ちょっと拡大して表示するとかでしょうか。
これも画像を直す手間は半端ないです。

【最後に】
一般的なノートとか安価なデスクトップとか、ゲーミングPC以外のVRAM1GBのメモリを持たないパソコンは切り捨てるということで良いんですよね?

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月18日(日) 00:42
by コマンダーヤンマーク
softya(ソフト屋) さんが書きました:やっぱりギリギリまで使うのは避けたいですね。
全部入れても最後の最後のいざと言う保険を残して80%ぐらいに留めたい所です。

サイズですが、512とか2の累乗サイズでない部分で無駄が出ているのかもしれません。
ただし、それで直るかは小規模な実験をしてみないとわかんないです。

あとは画像を減らすために、画像をパーツ化して同じ画像のパーツ部分をデータとして持たないようにするかですね。
専用のツールを作る手間とか、絵を見直すとか相当な手間が必要です。

それか画像を微妙に縮小して、ちょっと拡大して表示するとかでしょうか。
これも画像を直す手間は半端ないです。
お教えいただいたことも試して、何とか問題を解決しようと思います!ありがとうございます!

>一般的なノートとか安価なデスクトップとか、ゲーミングPC以外のVRAM1GBのメモリを持たないパソコンは切り捨てるということで良いんですよね?
今のところ考えてないです。
ですがクオリティを下げたバージョンに変更できるような設計も考えてみようと思います。(後まわしですが)

「教訓」
・高解像度のゲーム造りはVRAMの節約が重要
・ブレンドの関係ない処理落ちを見つけたらVRAMの状況を確認する。
みなさんいろいろ親切に教えてくださり、ありがとうございました。

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月18日(日) 01:49
by ru-pu
コマンダーヤンマーク さんが書きました:>画面モードを16bit カラーにすると半分に成るとの噂はありますが、今はどちらなのでしょうか?

とりあえず32bitでやっています。ためしに
SetGraphMode(WINDOW_WIDTH ,WINDOW_HEIGHT , 16 );
で16bitモードにしてみましたが効果は無かったです。
SetCreateGraphColorBitDepthで画像を16bitにすれば効果あるのではないでしょうか?

Re: 格闘ゲームキャラ描画の処理落ち

Posted: 2013年8月18日(日) 02:15
by コマンダーヤンマーク
>SetCreateGraphColorBitDepthで画像を16bitにすれば効果あるのではないでしょうか?

こっちの関数を使うんですね・・・。
効果ありました!鮮やかさはなくなったものの、処理落ちせずに動くようにはなりました。
どうしてもVRAMを削りきれないときはこれに頼ろうと思います!
ありがとうございます!