トップページ > 過去ログ > 記事閲覧
仮想フルスクリーン(?)と拡大負荷
名前:コーラ 日時: 2010/06/29 00:33

ワイド解像度のゲームを、その解像度に対応していないビデオカードで、しかもアスペクト比を 保ったままフルスクリーン表示する方法を考えています。 実は同じことを一度質問しておりまして hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=past&no=1310 「デスクトップ画面と同じ解像度のフルスクリーン画面に、描画可能画像に書き込んだゲーム画面を、 アスペクト比を計算してDrawExtendGraphすることによって実現するという方法」に対し、 「それだと負荷が高すぎるので、ゲーム解像度より高いビデオカードが対応している最低解像度のフル スクリーンモードにしてから、あとは同じようにアスペクト比を計算、DrawExtendGraphした方がいい」 と管理人さんから意見を頂いております。 その後しばらく考えたのですが、ゲーム解像度より高いビデオカードが対応している最低解像度に した時点で、ビデオカードがまずディスプレイにその解像度でアスペクト比を保ったスケーリングを 行い、その領域にさらにプログラムでアスペクト比を計算スケーリングするため、最終的に画面が かなり小さくなる可能性が高いことが分かりました。 また、最初の方法と同じように、デスクトップ解像度と同じ解像度のフルスクリーン画面に、ゲーム画面を 拡大して表示するという方法が市販ゲームでも使われているらしいことを知って(仮想フルスクリーン と言われている?)この方法ももう一度検討しようかなと考えていました。 ただ管理人さんが言われた通り負荷は高く、その対策を考えていたところ、 ウインドウモードでSetWindowSizeChangeEnableFlagやSetWindowSizeExtendRateを 使った場合、ウインドウを大きくしても負荷があまり上がらないことに気がつきました。 いずれもウインドウモード用の関数でフルスクリーンでは使えないようです。 しかしフルスクリーンでも似たような方法で拡大できれば、仮想フルスクリーン(?)を 低負荷で実現できると思うのですが、そんなことはDXライブラリの機能で可能でしょうか?

Page: 1 |

Re: 仮想フルスクリーン(?)と拡大負荷 ( No.1 )
名前:管理人 日時:2010/07/03 23:40

> その後しばらく考えたのですが、ゲーム解像度より高いビデオカードが対応している最低解像度に > した時点で、ビデオカードがまずディスプレイにその解像度でアスペクト比を保ったスケーリングを > 行い、その領域にさらにプログラムでアスペクト比を計算スケーリングするため、最終的に画面が > かなり小さくなる可能性が高いことが分かりました。 ディスプレイへの表示面積が小さくなってしまうということでしょうか? うーん、私とコーラさんでイメージしているアルゴリズムが異なっている気がします ただ、SetWindowSizeExtendRate の様に「描画画面以上のサイズにスケーリングして表画面に転送」する 手段は用意できましたので、恐らくコーラさんのご要望にお応えすることができると思います よろしければこちらのバージョンをダウンロードしてください http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) こちらのバージョンには DirectX9 版から無効になっていた ScreenCopy の引数 RECT *CopyRect が有効になっています この CopyRect に表画面に転送したい領域をメンバ変数で設定して、そのアドレスを渡せば指定の領域が 表画面一杯にスケーリングされる形で転送されます 例:画面解像度が 640x480 という前提で、画面中心の領域( ( 160,120 )〜( 480,360 ) )を   画面一杯に表示したい場合 RECT CopyRect ; CopyRect.left = 160 ; CopyRect.top = 120 ; CopyRect.right = 480 ; CopyRect.bottom = 360 ; ScreenCopy( &CopyRect ) ; よろしければお試し下さい m(_ _)m
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.2 )
名前:コーラ 日時:2010/07/04 05:58

>ディスプレイへの表示面積が小さくなってしまうということでしょうか? はい すいません、自分の環境の状態で具体的に書いてみます。 ディスプレイの解像度が1920*1080(通常時のデスクトップ画面解像度も1920*1080です) ゲーム解像度が960*600 ビデオカードが対応している、ゲーム解像度以上の最低画面解像度1024*768 プログラムの流れ ビデオカードが対応している、ゲーム解像度以上の最低画面解像度を取得し、その画面解像度に変更する。 今の場合、SetGraphMode(1024,768);で、画面解像度を1024*768にする。 ↓ 実際のゲーム画面を、サイズ960*600の描画可能な画像に描画していく。 ↓ 裏画面に、ゲーム画面をアスペクト比を保ったまま拡大し、貼り付ける。 今の場合、1024*768の裏画面に、960*600のゲーム画面を貼り付けるので、960*600(16:10)の ゲーム画面を1024*640(16:10)にDrawExtendGraphで拡大し、1024*768の裏画面にピッタリ貼り付ける。 (縦の解像度に差があるため、上下に黒帯ができる)その後ScreenFlip。 こうしますと、最初に画面解像度を1024*768にした時点で、ビデオドライバの自動スケーリングが 働き、1024*768の画面が、アスペクト比を保ったまま、ディスプレイに中央に寄せられ拡大されます。 (この結果既に、左右に黒帯が入ります) そして今度はプログラムで、1024*768の画面に、960*600(16:10)のゲーム画面をスケーリングし 1024*640(16:10)にして貼り付けるため、1024*768の画面内にさらに上下に黒帯が入ることになります。 図を描いてみました www1.axfc.net/uploader/Sc/so/130358.png アスペクト比を保ったままのスケーリングが二度行われて、画面が小さくなってしまいます。 初めから画面解像度をデスクトップ解像度と同じにすれば、それが一度で済むため、もっと 大きい画面にできます。 そうなると今度は負荷が問題になるわけですが・・・ RECT因数ですが、まだこれを書いてるときには使い方が分かりませんorz とりあえずデスクトップ解像度と同じ解像度の裏画面に、スケーリング拡大なしのゲーム画面を張り、 それをRECT因数で拡大して表画面に転送してみましたが、負荷はDrawExtendGraphを使った場合と 変わらないようです。
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.3 )
名前:管理人 日時:2010/07/04 16:17

ご説明ありがとうございます、状況を理解することができました それでしたら、画面解像度選択の条件に「16:10」を加えて 「16:10 で 960x600 以上の画面解像度」を選択するようにすれば良いと思うのですが如何でしょうか? > とりあえずデスクトップ解像度と同じ解像度の裏画面に、スケーリング拡大なしのゲーム画面を張り、 > それをRECT因数で拡大して表画面に転送してみましたが、負荷はDrawExtendGraphを使った場合と > 変わらないようです。 うーん、スケーリング拡大をしていない分、裏画面への描画面積は確実に減っているので負荷は軽くなっているはずなんですが・・・ ところで ScreenCopy の引数 CopyRect を使用する場合は描画可能画面は使用する必要はありませんので 「裏画面にゲーム画面を描画」  ↓ 「ScreenCopy でゲーム画面の領域を転送」 という風にしてみると、もう少し軽くなると思います 具体的には SetDrawScreen( DX_SCREEN_BACK ) ; 裏画面 0,0 〜 960,600 の領域にゲーム画面を描画 RECT CopyRect ; CopyRect.left = 0 ; CopyRect.top = 0 ; CopyRect.right = 960 ; CopyRect.bottom = 600 ; ScreenCopy( &CopyRect ) ; こんな感じです あと、すいません、申し上げ忘れていましたが ScreenCopy は ScreenFlip の代わりとして 使用するものですので、ScreenCopy の後に ScreenFlip を使用する必要はありません m(_ _)m
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.4 )
名前:コーラ 日時:2010/07/05 20:22

>それでしたら、画面解像度選択の条件に「16:10」を加えて >「16:10 で 960x600 以上の画面解像度」を選択するようにすれば良いと思うのですが如何でしょうか? あぁ、対応する解像度があればこれが一番軽くてまともそうですね@@; 全く気がつきませんでした。 ただ対応する解像度がない場合は使えないかもしれませんよね・・・。 一般的にビデオカードはどのような解像度に対応するのか調べようとしたのですが、そのような情報を 見つけられませんでした。 あれから色々実験してみました。 負荷の方ですが、描画可能画像を廃止して、裏画面に直書き→RECT引数で拡大しても 負荷はあまり変わらないようです。 どうもClearDrawScreenが怪しい感じで、裏画面の内ゲーム描画に使うところだけ、DrawBoxで 画面をクリアすると高速化しているようです。 (SetGraphModeでデスクトップ解像度と同じ画面解像度を確保しているが、裏画面からはRECT引数で 拡大して表画面にコピーするので、裏画面は左上の一部しか使っていない) 裏画面が拡大しているのでClearDrawScreenに時間がかかっているのかもしれません。 DrawBoxで塗りつぶす場合、3D機能を使うとZバッファが初期化されないせいか(過去ログより)画面が おかしくなりますが、下スレッドのClearDrawScreenZBufferと、RECT引数が同時に使えれば、こっちの 方が問題なく軽くなるかもしれません。 アスペクト比についても、デスクトップ解像度の比と、ゲーム解像度の比を比べて、RECT引数を調整すれば 問題はなさそうです。 しかしそれでもウインドウモードでウインドウを大きくする方法が一番軽いんですが これと同じような軽さをフルスクリーンで実現するのは、やっぱり無理でしょうか? 追記 普通に画面960*600の表と裏画面を用意して描画したときと、 1920*1080の表と裏画面を用意、裏画面の内SetDrawArea(0,0,960,600);で左上部分だけを使い、 RECT引数で表画面に拡大したときでは、3Dシーンで微妙に画面の移り方が変わっています。 表画面へ転送される際の引き伸ばしは考慮してあるのですが、それ以前にカメラの変換行列が変わったような感じです。 それに気づいて、SetCameraScreenCenter( 960/2, 600/2 );、SetupCamera_Perspective( 60 * PHI_F / 180.0f ) ;、 SetCameraPositionAndTargetAndUpVec()に固有の値を入れてみるなど対処したのですが、やはり違ったままです。 推測される原因などありましたらご教授お願いします。 質問ばかりですみません・・・。
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.5 )
名前:管理人 日時:2010/07/11 13:57

> ただ対応する解像度がない場合は使えないかもしれませんよね・・・。 > 一般的にビデオカードはどのような解像度に対応するのか調べようとしたのですが、そのような情報を > 見つけられませんでした。 確かに、16:10の解像度自体が最近普及してきたものですから、どの液晶モニタでも対応している 一般的な16:10の解像度となると最低でも 1280x800 とかになってしまいますね・・・ > どうもClearDrawScreenが怪しい感じで、裏画面の内ゲーム描画に使うところだけ、DrawBoxで > 画面をクリアすると高速化しているようです。 なるほど、画面クリアは ClearDrawScreen をしてしまうと使用していない領域までクリア処理が行われるので 無駄になってしまいますね ClearDrawScreen にも ScreenCopy と同じように RECT 構造体で領域を指定できるようにしたバージョンを アップしましたので、よろしければお試しになってみてください m(_ _)m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) 使用例: RECT Rect ; Rect.left = 0; Rect.top = 0; Rect.right = 960; Rect.bottom = 600; ClearDrawScreen( &Rect ); 因みに負荷軽減策としてはこれで全てですので、ClearDrawScreen の領域指定をしても ウインドウモードの方が軽いとなりますと、それはもうそういうものだと認めるしかないと思います・・・ 思えばウインドウモードで同様のことをする場合裏画面はゲーム画面の解像度なのに対して フルスクリーンの場合は裏画面もデスクトップと同じ解像度なので、その辺りの違いが ウインドウモードの方が高速に動作する原因かもしれません ( フルスクリーンモードの場合は裏画面と表画面の解像度を別々にすることはできないので、全く同じ条件に  することはできません・・・ ) > 普通に画面960*600の表と裏画面を用意して描画したときと、 > 1920*1080の表と裏画面を用意、裏画面の内SetDrawArea(0,0,960,600);で左上部分だけを使い、 > RECT引数で表画面に拡大したときでは、3Dシーンで微妙に画面の移り方が変わっています。 すいません、3Dを使用する場合今回のような画面の一部を仮の解像度の小さな画面として 使うには既存の機能だけでは役不足でした DXライブラリでは SetDrawArea で描画領域を指定して SetCameraScreenCenter で描画領域の中心を 指定しても、あくまで画面全体を使用した3D表現の一部分だけを映すような描画結果になるので、 描画領域のサイズと同じ画面解像度にしたときと同様の描画結果を得ることはできません それを実現するにはスケーリングを行う必要があるので、それを行うための関数を追加しました // 3D描画のスケールをセットする int SetDraw3DScale( float Scale ) ; 全く同じカメラ設定でも画面解像度が2倍になったら実際にレンダリングされるピクセル換算の面積は 2倍になります、ということは解像度が大きくなった分だけ描画結果を小さくしてあげないと 今回のように画面の一部分をより解像度の低い画面として使用することができないということだったんです なので、もし 900x600 のゲーム画面に対して画面解像度が 1960x1200 だった場合は SetDraw3DScale( 900.0f / 1960.0f ) ; という風に設定してみてください、恐らく描画結果が実際に 900x600 の時と同じになると思います
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.6 )
名前:コーラ 日時:2010/07/15 08:15

管理人さん、本当に色々とありがとうございます ClearDrawScreenにもrect引数を使って負荷を軽減できました。 SetDraw3DScaleを使用して、カメラの映り方を同じにすることにも成功しました。 ところでSetDraw3DScaleの設定ですが DXライブラリでは解像度の設定に関わらず、初期状態でカメラが 捕らえている縦方向の範囲が一定なので、例のように横方向を基準に するのではなく、縦方向を基準にスケーリングしておくと、今回のような ケースでは同じ映り方にできるのですね。 (デスクトップと同じ解像度の縦横比が、ゲーム解像度と 同じとは限らないため、横方向の移っている範囲が違っていることがある。 そこを基準にスケーリングをすると、違った横方向の映る範囲を 基準にスケーリングが起こるようです)
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.7 )
名前:管理人 日時:2010/07/18 04:14

すいません、現在のバージョンを Windows7 と Vista でテストしてみたのですが、ScreenCopy に 転送元矩形を指定する機能は Windows7 と Vista では正常に動作しませんでした orz 代替機能は用意できたのですが、Windows7 と Vista で動作するようにする都合上 ScreenCopy に RECT 構造体を渡す機能は削除することになりました m(_ _;m お手数で申し訳ありませんが、こちらのバージョンをダウンロードしてください http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) // ビューアー http://homepage2.nifty.com/natupaji/DxLib/DxLibModelViewerTest.zip 代替機能として追加した関数は以下の関数です // ScreenFlip 時に表画面全体に転送する裏画面の領域を設定する( DxLib_Init の前でのみ使用可能 ) int SetGraphDisplayArea( int x1, int y1, int x2, int y2 ) ; 裏画面の内容のどの部分を表画面一杯に表示するかを指定する関数です DxLib_Init を呼ぶ前に使用する必要があるという違いはありますが、 基本的に引数は ScreenCopy に RECT として渡していたパラメータそのままです 例えば RECT Rect ; Rect.left = 0; Rect.top = 0; Rect.right = 900; Rect.bottom = 600; ScreenCopy( &RECT ); とされていた場合は ScreenCopy を呼んでいた箇所は ScreenFlip(); と ScreenFlip を呼ぶだけにして、代わりに DxLib_Init の前に SetGraphDisplayArea( 0, 0, 900, 600 ) ; という記述を増やしてください m(_ _;m > DXライブラリでは解像度の設定に関わらず、初期状態でカメラが > 捕らえている縦方向の範囲が一定なので、例のように横方向を基準に > するのではなく、縦方向を基準にスケーリングしておくと、今回のような > ケースでは同じ映り方にできるのですね。 ご指摘の通り縦基準でスケーリング値を決定するのが正解です orz
Re: 仮想フルスクリーン(?)と拡大負荷 ( No.8 )
名前:コーラ 日時:2010/07/24 06:05

管理人さん、対応してもらってありがとうございます。 SetGraphDisplayAreaを使ってみたところ 問題なく、裏画面の一部をだけを使った、フルスクリーン化に成功しました。 負荷の方ですが、描画可能な可能な画像を裏画面いっぱいにDrawExtendしていた頃に 比べて、FPSが最大で1.5倍程になりました。 これで個人的に現段階としては ワイド+フルスクリーン+アスペクト比固定、といったところに決着を付けられそうです。

Page: 1 |