いつもお世話になっております、山崎です。
今回は、拡大・縮小表示についてお伺いに参りました。
現在、ライフルのスコープを覗いたときの様子をどう表現しようかと考えています。
スコープの倍率はできれば10倍くらいまで可能にしたいと考えています(最低でも5倍)。
また、3Dやポリゴンは可能であれば使用を避けたいと思っています。
精密な照準を必要とするゲームにしたいと考えているので、拡大して画像を荒くするのは避けたいと思っています。
スコープの倍率が最大の10倍のとき、用意した元の画像はそのままの大きさで描画され、
スコープを覗いていない時(倍率1倍)のとき、用意した元の画像は10分の1の大きさで描画される、
といった方式にしたいと思っています。
実質、画像を引き伸ばして描画するような拡大は無いことになります。
スコープの倍率は連続的で、倍率によってスコープから見える風景も
滑らかにズームイン・ズームアウトされるような仕様にしたいと考えています。
そこで、次のようなアルゴリズムを考えました。
1.MakeScreen()で元の画面サイズの10倍のサイズのサブ画面を用意する。
2.MakeGraph()で、元の画面サイズの10倍のサイズのグラフィック領域を用意する。
3.サブ画面に必要な風景を描画する。
4.GetDrawScreenGraph()で、スコープの倍率と焦点に応じた領域をサブ画面から切り取り、
用意したグラフィックハンドルに保存しておく。
5.裏画面全体に切り取ったグラフィックを描画する。
6.ScreenFlip()
試しに、画面サイズ10倍ではなく3倍で実行してみたのですが、
3倍程度でもFPS=15前後と非常に重くなってしまいました。
以下が、試してみた際の主なコードです。倍率の変更や焦点の移動は省いています。
倍率1倍のときの見え方を想定したコードです。
//-----------最初に一度だけ実行する部分------------------
int SubScreen=MakeScreen(640*3,480*3);
int GHandle=LoadGraph("Test.PNG");//風景。画像サイズは640*3×480*3
int SubScreenHandle=MakeGraph(640*3,480*3);
//----------------ループする部分-------------------------
SetDrawScreen(SubScreen);
DrawGraph(0,0,GHandle,FALSE);//元の画像そのままの大きさで、サブ画面に風景を描画
GetDrawScreenGraph(0,0,640*3,480*3,SubScreenHandle);//倍率1倍のときを想定。風景全体を切り取る。
SetDrawScreen(DX_SCREEN_BACK);
DrawExtendGraph(0,0,640,480,SubScreenHandle,FALSE);//裏画面に切り取った風景を描画
ScreenFlip();
私の作ってみた上のコードでは、重くてとてもゲームになりません。
画像の拡大を行わず、縮小だけでズームイン・ズームアウトを表現するにはどうしたらよいでしょうか。
スコープを覗いた時のような拡大・縮小表示
Re:スコープを覗いた時のような拡大・縮小表示
>私の作ってみた上のコードでは、重くてとてもゲームになりません
そりゃまぁそうでしょうね。
VGAサイズの時ですら GetDrawScreenGraph()はあまり軽い処理ではなく、
毎フレーム連続して使うようなものではないですから。
縦横それぞれ 10倍もの面積を持っているならなおさらです。
というわけで、まず4の処理を何とかして下さい。
わざわざ切り取って新たなハンドル使わなくても SubScreenに必要な絵は
そろっているので後は DrawRectRotaGraphを使うとか
DrawPolygon / DrawPolygonBaseを使って UVで切り取って表示すればいいはずです。
そすると、必然的に2のハンドルも不要になります。
さて、これで重くなる原因の1つは無くなるのですが、これでも単純に
描画面積が大きいので重い可能性があります。
VGAなら 0.3Mピクセルですが、縦横それぞれ10倍ともなると面積 100倍なので
30Mピクセルです。
よほど豪華なシステムでもなければちょっと厳しいです。
では、その場合どうするかというと、細かく説明すると話が長くなるので端的に纏めると
ソフト的に MIPMAP(異なる解像度のテクスチャを使い分ける)処理を行うことです。
(ケースによっては高解像度のテクスチャは複数に分割して持った方がいいかもしれません)
あとはどのテクスチャを使用するかをズーム値から求め、内部座標からズーム値に合わせた
表示座標に変換して表示します。
勿論、ズームの結果画面外であることが判ったら表示はしないようにします。
描画先は従来通りサイズですし、無意味に不必要なところのレンダリングを
しないで済むのでそれなりに軽くなるはずです。
Re:スコープを覗いた時のような拡大・縮小表示
Justyさん
ご返信、誠にありがとうございます。
やはり私のやり方では難しいようですね・・・。
さすがに10倍じゃ無理なのかなとは思っていましたが・・・。
高性能のパソコンで実行することを前提としたゲームではないので、
私のやり方での実装はあきらめる事にします。
しかしDrawRectRotaGraphなどを使うという方法は参考になりました。
また機会があれば是非とも使ってみたいと思います。
MIPMAPについて、自分でちょっと調べてみようと思います。
実装するのには私の腕ではだいぶ時間がかかりそうです。
解像度の違う絵を複数準備する、という発想はありませんでした。
いろいろ教えていただき本当にありがとうございました。
ご返信、誠にありがとうございます。
やはり私のやり方では難しいようですね・・・。
さすがに10倍じゃ無理なのかなとは思っていましたが・・・。
高性能のパソコンで実行することを前提としたゲームではないので、
私のやり方での実装はあきらめる事にします。
しかしDrawRectRotaGraphなどを使うという方法は参考になりました。
また機会があれば是非とも使ってみたいと思います。
MIPMAPについて、自分でちょっと調べてみようと思います。
実装するのには私の腕ではだいぶ時間がかかりそうです。
解像度の違う絵を複数準備する、という発想はありませんでした。
いろいろ教えていただき本当にありがとうございました。