Direct3Dで描画が不安定になります

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
cattail
記事: 75
登録日時: 10年前

Direct3Dで描画が不安定になります

#1

投稿記事 by cattail » 9年前

ごぶさたしています。またよろしくお願いします。
Direct3Dを使用してマップに人物を表示しています。
少しデータが大きくなっています。
timeSetEventを使用して秒間1000回の割り込みをかけてその中で描画していて、
FPSが落ちたら描画をスキップして描画回数を合わせるようにしています。
早いPCで60FPSほど出ている時は問題なかったのですが、
遅いPCで試すと最初は35FPSほどで動いているのですが、
画面を動かしていないのに、30秒から60秒くらいすると15FPSと35FPSを行ったり来たりするようになり安定しません。
timeSetEventの割り込み回数を減らしてみたり、描画をWM_APPの中に移してみたりと、
ここ2、3日がんばって調べているのですが原因が分からず対処できていません。
なぜこのような事が起こるのか、何か原因の心当たりがある方がいらっしゃいましたら教えて頂けたらと思います。
よろしくお願いします。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#2

投稿記事 by cattail » 9年前

色々いじっていますが未だに解決していません。
もしかすると遅いPCの方がIntel HD Graphicsなので、
そもそも15FPSの能力しか発揮できないのかもしれません。
一番低い値を設定して動かすようにすればいいのかなと思っています。
それだと何だか自分の勘違いというか認識不足というかお恥ずかしいです…。
でも、ちょっとそれでやってみます。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#3

投稿記事 by cattail » 9年前

とりあえず低い値15FPS+3前後を基準とすることで速くなったり遅くなったりはしなくなりました。
これでいいのかどうかはわかりません。
質問の説明がおおまか過ぎて、日記になってしまいました。すみません。
でもここに書いているうちに、何か今回のように別の考えが出てきたりして良かったです。
ありがとうございました。またよろしくお願いします。

ISLe()

Re: Direct3Dで描画が不安定になります

#4

投稿記事 by ISLe() » 9年前

直接の回答ではありませんが
わたしなら最終的には命令を発行する順序が重要なので割り込みの中で描画はしないですし
ディスプレイの周波数以上で画面を更新しても無意味なので秒間1000回も描画処理を呼びません。

垂直同期を切って遅延の原因がどこにあるのかきっちり確認した上で
描画が原因で垂直同期に合わせるならディスプレイの表示タイミングに合わせて調整しないとブレますし
描画が原因でないなら処理単位の時間軸そのものを伸ばす対策が必要です。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#5

投稿記事 by cattail » 9年前

ISLe()さん、お返事を頂いてありがとうございます。

割り込み中の描画ですが、命令の順序以外では問題が起こる可能性はありますでしょうか?
今は秒間1000回の割り込み中に描画するのは最大60回になっています。
FPS60の時は15回(ほぼ)空で回して1回描画を繰り返す、というようにしています。こういうのはダメでしょうか?

グラフィックボードの垂直同期を切って原因を探すということでしょうか?
恥ずかしながらあんまり理解できていないのですが、
垂直同期に合わせて描画しないといけないのでしょうか?
今はそういうことを全然やっていません。
上記「FPS60の時は15回空で回して1回描画を繰り返す」のようにどんどん描画命令を出しています。

ISLe()

Re: Direct3Dで描画が不安定になります

#6

投稿記事 by ISLe() » 9年前

秒間1000回の割り込みというのは、1msごとに順序正しく呼び出されると想定しているということでしょうか。
それは間違っているので根本的に考え方を改める必要があると思います。

垂直同期は、Direct3Dのデバイスを作成するときやPresent関数を呼び出すときに指定するフラグで無視するかどうかを選択できます。
おっしゃるとおり、グラフィックボードのドライバで強制的に同期させることもできるので、そうであればそちらの設定を変更する必要があります。
また、ウィンドウ表示の場合には、Aeroテーマの有効なデスクトップでは強制的に同期されるはずなので、互換性表示で一時的にクラシックテーマにするなどの対策も必要になるかと思います。

垂直同期を切れば、60FPS以上出るようになります。
現状、60FPSで安定するというのもたまたまでないことを確認してください。

垂直同期に合わせることと、フレームレートを維持することは、別の問題ですので、フレームの進行を安定させるためには、それぞれに両方とも解決する必要があります。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#7

投稿記事 by cattail » 9年前

ISLe()さん、何度もすみません。
1000回割り込みと割り込み内描画は考え直します。
自分の勝手な思い込みでやってしまっていました。

その他色々教えてくださってありがたいです。
Aeroテーマとかクラシックテーマとか、まるで知らないので調べてから、
対処したいです。でも、できるかどうかかなり怪しいのですが…。
同じところをやり過ぎて少々イヤになっているところです。

少しでも解決しましたらご報告いたします。
ありがとうございました。

ISLe()

Re: Direct3Dで描画が不安定になります

#8

投稿記事 by ISLe() » 9年前

FPS制御については過去ログにたくさんの記事があります。
わたしが使う実装についてはこちらのトピックで詳しく回答してます。

秒間1000回の割り込みにFPS制御以外の意味があるのなら教えてください。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#9

投稿記事 by cattail » 9年前

FPS制御についての過去ログをご紹介して下さってありがとうございます。
よく読んで参考にしたいと思います。
ありがとうございます。

秒間1000回の割り込みについてですが、
以前、MIDI演奏のプログラムを書いていまして、
その時、秒間1000回の割り込みをかけてリアルタイムにデータを取得し発音させてその楽器名称、音階を表示していたのです。
FPSや描画には関係ありませんが、機能をそのまま受け継ぎたかったというのがあったのですが、
今回のゲーム制作には使わない機能なので無くしていこうと考えてます。

ISLe()

Re: Direct3Dで描画が不安定になります

#10

投稿記事 by ISLe() » 9年前

MIDIのドライバで必要だったということでしょうか。

ドライバレベルで割り込みを使うのは分かりますが、秒間1000回の根拠はやはり分からないですね。
MIDIに割り込み信号ありませんでしたっけ。

アプリケーションレベルならなおさらポーリングする必要がない気がします。
ウィンドウズはリアルタイムOSではないので、もとからそういう使い方に向いていません。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#11

投稿記事 by cattail » 9年前

分かり難くてすみません。
ドライバなのかさえ自分でもわかっていませんが、
MCIを使わない低水準な方法でMIDIを再生する、みたいなHPで見て作りました。
楽器の発音とか消音もプログラムでやるので1000回の割り込みは必要らしいです。

描画のどの部分が遅延してるのかさえわかりません。
コアな所は本とかネットから集めて自分なりに合成してるので、
理解していない部分も多いんですよね。
再起呼び出しに重複みたいのがあってそこに遅延する要因があるような気がするのですが、
頭がこんがらがってピョーンって感じです。

ISLe()

Re: Direct3Dで描画が不安定になります

#12

投稿記事 by ISLe() » 9年前

確認したところ、timeSetEventのコールバックで遅延しても、再入する(前の呼び出しから戻る前に新たに発生する)ことはないようです。

主要部分が割り込みに依存していなければ、ウェイトを取り除くのは簡単にできるのですが、それができないということは、割り込みにべったり依存しているのでしょうか。

わたしもそんなふうだと 同じように頭がこんがらがってしまうと思います。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#13

投稿記事 by cattail » 9年前

割り込み内での描画とその他移動などの処理を全てwindowsloop内に移し、
割り込み内ではアニメーション時間の進行のみを行うようにしました。
コードを簡略化して載せました。

windowモードで動いています。
メッシュが多くなると38FPS~15FPSを行ったり来たりして、
メッシュの少ない時は60FPSで動いていますが、たぶんココでも遅延してると思います。
やはり描画の遅延は相変わらずです。
描画のどこで遅延が発生しているのか調べていますがわかりません。
デバッガにそういう機能はあるのでしょうか?

コード:


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) 
	{

		//その他の処理など

		//ゲーム終了
		case WM_KEYUP:

			if( wp == VK_ESCAPE ){

				//ゲーム終了選択へ
				
			}


		//その他の処理など

	//ゲームのメインループを呼び出す/////////////////////

	game_loop();//ここで呼び出していいのかな?

	/////////////////////////////////////////////////////


default:
		return(DefWindowProc(hWnd, msg, wp, lp));
	}
	return (0);
}


void CALLBACK timercall(UINT uiID, UINT uiNo, DWORD dwCookie, DWORD dwNo1, DWORD dwNo2) {

	//1秒間に何回割り込みが入っているか調べる
	time_count2 = time_count2 + 1;
	if(time_count == 0){time_count = timeGetTime();}	//今の時間確保
	if(time_count + 1000 < timeGetTime()){			//1秒計測
		time_count3 = time_count2;			//time_count3は画面表示用
		time_count2 = 0;
		time_count = 0;
	}

	//アニメーションtimeを進める
	Clock_forward();

}


void game_loop(){

	//カーソルがwindowの外に出ないようにする
	cur_winout_set();

	//その他 マウス、キー入力やキャラ移動処理など色々


	//レンダリングする
	Render();


}


ISLe()

Re: Direct3Dで描画が不安定になります

#14

投稿記事 by ISLe() » 9年前

「windowsloop」とは聞かない単語ですね。

提示されたコードを見ると、ウィンドウプロシージャからアプリケーションのメイン処理が呼び出されていますが、フレームレートを重視する場合において、この方法は一般的ではないと思います。

フレームレートを重視する場合、メッセージループの中でアプリケーションのメイン処理を呼び出すようにして作成します。



秒間1000回、1msごとの割り込みを前提にするというのは、現実の時間に依存します。

60FPSを前提にするというのは、1コマごとの(内部)処理が60回呼びだされた時点で1秒経過しているのが『ちょうど良い』という仕様の話ですから、『60回呼びだされた時点で1秒経過している』のが必須ではありません。

この違いが分かりますか?

プログラミングでは抽象化が重要ですが、抽象化は実装だけの話ではありません。
時間を抽象化すれば、1コマごとの(内部)処理が60回呼びだされた時点で10秒経過している『デバッグにはちょうど良い』実装も容易になります。



1コマ分の内部の数値を更新する処理、1コマ分の描画処理、それぞれ関数に分離できているでしょうか。

分離できているならその関数を呼び出す前と後で高性能タイマーの値を取得して経過時間を知ることができます。

Visual Studio Communityならプロファイラが使えるのでコードの変更なしに関数の呼び出しに掛かった時間を測定できます。
プロファイラを使うと実行負荷が高くなるので、現実時間に依存したコードのデバッグはやはり困難です。

ISLe()

Re: Direct3Dで描画が不安定になります

#15

投稿記事 by ISLe() » 9年前

Direct3Dチュートリアルのサンプルコードでウィンドウプロシージャやメッセージルーブの基本を学ぶことができます。
SDKに含まれている、あるいはMSDNサイトからのダウンロードで入手できます。


あと、PCのスペックが低くて負荷が高いときにFPSが落ちるのは避けられないことです。
わたしがしているのは、FPSが下がっても再生時間が変わらないようにするとかの対策に向けた話です。


timercallのロジック、おかしくないですか。
1秒経過してリセットしたあと、1回置いて、次の呼び出し時に開始時間記録してますね。
そもそも、経過時間チェックするなら、コールバック使う必要がないのでは。

Clock_forward関数の中でどうやって時間を管理しているのかも重要ですけども、遅延がなくても正確にカウントできていないので、以前書いたとおり、60FPSで安定しているというのもたまたまということになりますかね。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#16

投稿記事 by cattail » 9年前

ISLe()さん、細かい所まで教えて頂いて恐縮です。
windowsloop…てへへ、僕の造語ですね。
色々と直すところはありますが、
まずは、game_loop();をメッセージループから呼び出すことをやってみます。
単純にメッセージループの中に置けばいいのでしょうか?
Direct3Dチュートリアルのサンプルコードを見てきます。

ISLe()

Re: Direct3Dで描画が不安定になります

#17

投稿記事 by ISLe() » 9年前

cattail さんが書きました:まずは、game_loop();をメッセージループから呼び出すことをやってみます。
単純にメッセージループの中に置けばいいのでしょうか?
Direct3Dに限らず、Win32 APIを使ったゲームプログラミングの基本事項なので、検索すれば解説サイトがたくさん見付かると思います。
とりあえずWin32のPeekMessage関数を使ったメッセージループというのを調べてみてください。

『Win32 ゲームプログラミング』でGoogle検索

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#18

投稿記事 by cattail » 9年前

とりあえずメッセージループは以下のようにしてみました。
ゲームは同じように動いています。

コード:


    //ゲームループ
    while ( TRUE ) {
    //メッセージをCALLBACK関数に送る
        if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {

			if ( !GetMessage(&msg, NULL, 0, 0) ) break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);

		} else {
			//ゲームのメインループを呼び出す/////////////////////

			game_loop();

			/////////////////////////////////////////////////////
			Sleep(1);
		}
	}

そこで、ISLe()さんがおっしゃっていた、
「1コマ分の内部の数値を更新する処理、1コマ分の描画処理、それぞれ関数に分離できているでしょうか。
分離できているならその関数を呼び出す前と後で高性能タイマーの値を取得して経過時間を知ることができます」
を試してみました。
すると、以下の関数を呼び出す所で遅延が発生していることがわかりました。
やった! ありがとうございます!
でも、この関数は「逆引き大全500」という本にあったもので、自分ではよくわかりません。
でもこの関数に問題があると思えないのです。
すると、残るのはデータでしょうか?
5000ポリゴンほどのスキンメッシュの中に問題があるデータを含んでいるのではないかな?
と、思っています。

コード:


VOID SKIN_MESH::DrawFrame(LPDIRECT3DDEVICE9 pDevice,LPD3DXFRAME pFrameBase)
{
	MYFRAME* pFrame=(MYFRAME*)pFrameBase;
    MYMESHCONTAINER* pMeshContainer = (MYMESHCONTAINER*)pFrame->pMeshContainer;	

    while (pMeshContainer != NULL)
    {
        RenderMeshContainer(pDevice,pMeshContainer, pFrame);
        pMeshContainer = (MYMESHCONTAINER*)pMeshContainer->pNextMeshContainer;
    }
    if (pFrame->pFrameSibling != NULL)
    {
        DrawFrame(pDevice,pFrame->pFrameSibling);
    }
    if (pFrame->pFrameFirstChild != NULL)
    {
        DrawFrame(pDevice,pFrame->pFrameFirstChild);
    }
}


cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#19

投稿記事 by cattail » 9年前

MicrosoftのMView.exeで例のスキンメッシュを表示してみました。
すると5秒間隔くらいで92FPSと55FPSの間を行ったり来たりします。
どうやらデータの作りに問題があることが濃厚です。

データを作り直して(どこが悪いかわかりませんが)FPS表示及びFPS速度が落ちても
同じように動作できるようになりましたらご報告します。
ありがとうございました!
とくにISLe()さん、色々ご教授いただきありがとうございました!
ISLe()さんのブログはお気に入りにしてFPS部分の再作成の時にじっくりと参考にさせていただきます。

ISLe()

Re: Direct3Dで描画が不安定になります

#20

投稿記事 by ISLe() » 9年前

メッシュ自体を軽量化するとなると、プログラムだけでなく、デザインの段階で考慮していく必要があります。

どんなモデルなのか分からないので具体的なことは言えませんが
スキンメッシュでも、真っ裸でなければ服の部分とそれ以外で分割して描画順を工夫するとか、そもそも服で隠れる部分は作らないとか。

cattail
記事: 75
登録日時: 10年前

Re: Direct3Dで描画が不安定になります

#21

投稿記事 by cattail » 9年前

ISLe()さん、ご返事いただきありがとうございます。
モデルの作り方から考え直していきたいと思います。
今使っているスキンメッシュじゃない大きなデータを表示させて実験してみようとも思っています。

閉鎖

“C言語何でも質問掲示板” へ戻る