質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

Q&A

解決済

3回答

6120閲覧

ループの時間を短くするには?DirectX, C++

tiwatiwa

総合スコア70

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

0グッド

3クリップ

投稿2016/02/02 16:20

DirectXとC++でゲームを作っています。
これまでに、とりあえず何も描画しないソースを作りました。

しかし、時間計測すると1ループするのに16~18ミリ秒かかるみたいです。
どこにそんな時間がかかるのか分かりません。

まだ描画も何もしていないため1~2ミリ秒ほどで1ループくらいできるだろうと思っていました・・・。

ヒントでもいいので教えていただけると嬉しいです。
(すでに2日も悩んでいました・・・)

ちなみに、メインループは以下のように作りました。

C++

1for(;;) 2{ 3 if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) 4 { 5 // WM_QUITメッセージを受け取る(0) または エラー発生時(-1)にループを終了する。 6 if (GetMessage(&msg, NULL, 0, 0) <= 0) 7 { 8 break; 9 } 10 TranslateMessage(&msg); 11 DispatchMessage(&msg); 12 } 13 else 14 { 15 const DWORD clear_flag = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER; // Zバッファの設定 16 const D3DCOLOR clear_color = D3DCOLOR_XRGB(11, 18, 155); // 背景色 17 // シーンのクリア 18 d3dDevice_->Clear(0, NULL, clear_flag, clear_color, 1.0f, 0); 19 // デバイスに描画開始を通知 20 d3dDevice_->BeginScene(); 21 // デバイスに描画終了を通知 22 d3dDevice_->EndScene(); 23 // 画面をバックバッファと入れ替える 24 d3dDevice_->Present(NULL, NULL, NULL, NULL); 25 } 26}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

PresentationIntervals が、D3DPRESENT_INTERVAL_DEFAULT に設定されているのでしょう。
D3DPRESENT_INTERVAL_DEFAULT=D3DPRESENT_INTERVAL_ONE ですので、
Present 関数は、垂直帰線信号を待ちます。垂直帰線は通常60Hzですので、一回のループに必ず、1秒/60=16ms かかります。
これ以上の速度で画面更新を行っても、画面には現れません。ですので、これ以上速くすることを考えるのではなく、1ループ必ず16ms以内に終了するようにプログラムを書くべきです。
垂直帰線信号の事を正しく理解し、これ以上早くするには、垂直帰線信号を待たない、D3DPRESENT_INTERVAL_IMMEDIATE を使うか、144Hzなどの60Hz以上の更新間隔持っていたり、G-Sync対応のゲーミングモニターを使わなければなりません。

投稿2016/02/02 19:36

編集2016/02/02 19:38
katsumiy

総合スコア479

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/02/03 12:00

PresentationIntervalsの設定がデフォルトになっていると1/60秒で動くようになってるんですね!はじめて知りました。 FPS機能を付けようとしたときに30FPSは正常にできたのですが、60FPSに設定すると急に変な動きになるので60FPS以上にはできないのかなと気になっていただけなのですが・・・ 1ループ必ず16ms以内に終了するようにプログラムを書くべきというのはその通りです! 情報ありがとうございました!
guest

0

おそらく、Presentメソッドが「垂直同期」待ちをしているためだと思います。
Direct3Dデバイスを作成するときに渡すパラメータによってはPresentメソッドの中で適切な表示タイミングになるまで「待ち」が発生するので、結果的にループ速度が遅くなるわけです。ディスプレイのリフレッシュレートは多くは59.94Hzか60Hzで約16.6ミリ秒間隔となり、ご質問の計測時間とだいたい一致しますね。

垂直同期を取らずに画面に表示しようとすると、特に動きのあるものでは上下で映像がずれたりして見苦しくなるので、適切なタイミングで表示する必要があるのです。

対応策としては「トリプルバッファリング」という手法がお手軽でおすすめです。バックバッファーを2枚用意することで垂直同期と非同期で描画処理が行えるようになり、Presentが垂直同期待ちをしなくなります。
これは、ディスプレイのリフレッシュレートに影響されずにゲーム内のフレームレート(fps)を独自に制御したい、というようなときにも使われる手法です。

当然メモリ消費量が増えるので、しょぼいマシンの場合はテクスチャーなど他で使えるメモリが減るという副作用がありますが、今時の数百メガとかギガというオーダーでVRAMを乗っけているマシンなら全く問題ありません。
VRAMがシステムメモリと共有の場合は、多少は影響が出る可能性は否定できませんが、それでも今時のマシンなら無視できる程度でしょう。

Direct3Dのバージョンやフレームワーク(DXUT等)によって設定方法が違うので、詳しくはリファレンスを参照してください。

投稿2016/02/02 21:19

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/02/03 12:08

垂直同期というのは初めて知りました。垂直同期に対応したFPS制御を作りたいと思います。 情報ありがとうございました!
guest

0

こんにちは。

外してたら、すいません。

時間、どうやって測ってますか?
もし、GetTickCount()を使って計測されたのでしたら、これは15mSec程度の分解能しかありません。
ここを参考にもっと高精度なタイマで計測することをお勧めします。
Visual Studio 2012以降をお使いなら、std::chrono::high_resolution_clock()も良いと思います。

投稿2016/02/02 16:54

編集2016/02/02 16:55
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/02/03 10:35

timeGetTime()を使って計測しました。 今回は時間取得の関数は関係なかったみたいですが、std::chrono::high_resolution_clock()は初見だったので調べてみます。 情報ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問