画像の擬似3D表示について
画像の擬似3D表示について
はじめまして、YKと申します。
Dixqさんのページは説明がわかりやすく、いつも参考にさせてもらっています。
この度はタイトルに書いたように、画像の擬似3D表示について伺いたいことがあります。
よくゲームである魔方陣等の描写ですが、画像を擬似3D表示、回転のアルゴリズムがどうもわかりません。
画像の倍率を変えて回転描写すればいいのでは、と考えたのですが自分ではうまくできませんでした。
アルゴリズム、簡単な例などわかる方よろしくお願いします。
ちなみに私のプログラミング暦は今年で3年です。
Dixqさんのページは説明がわかりやすく、いつも参考にさせてもらっています。
この度はタイトルに書いたように、画像の擬似3D表示について伺いたいことがあります。
よくゲームである魔方陣等の描写ですが、画像を擬似3D表示、回転のアルゴリズムがどうもわかりません。
画像の倍率を変えて回転描写すればいいのでは、と考えたのですが自分ではうまくできませんでした。
アルゴリズム、簡単な例などわかる方よろしくお願いします。
ちなみに私のプログラミング暦は今年で3年です。
Re:画像の擬似3D表示について
>よくゲームである魔方陣等の描写ですが
よくありすぎてどういう動きを目標としているのか特定できないのですが、
要するに2Dの縦か横にスケーリングして潰した上で画面に対してその形状を保ったまま
画像だけを回転させたいということですか?
Re:画像の擬似3D表示について
なるほど。
環境が不明瞭なので一般的に話になりますが、DirectXや OpenGLなど大抵の場合
4頂点を指定してトライアングルストリップかトライアングルファンを
表示する機能がありますので、それを使うことになります。
で行列計算を使って表示する4点の座標を求めて、その4頂点描画機能を使って
表示するのが一番いいですね。
ここから先は行列がわからないとちょっとつらいかもしれません。
座標変換
ttp://www.geocities.co.jp/SiliconValley-Bay/4543/Rubic/Mathematics/Mathematics-2.html
ttp://www.mech.tohoku-gakuin.ac.jp/rde/contents/course/robotics/coordtrans.html
ttp://nis-lab.is.s.u-tokyo.ac.jp/nis/CG/cgtxt/cg2/cg024.htm
まず、画像の中心座標を原点としたときの回転・スケーリングしていないときの
4点の座標を出します。
これは縦横の画像サイズがわかっていれば出せます。
画像サイズがそれぞれ imageSizeX、imageSizeYだとすると
[color=#d0d0ff" face="monospace]
struct position
{
float x, y;
};
position pos[/url] =
{
{ - imageSizeX/2, - imageSizeY/2 },
{ + imageSizeX/2, - imageSizeY/2 },
{ + imageSizeX/2, + imageSizeY/2 },
{ - imageSizeX/2, + imageSizeY/2 },
};
[/color]
となります。
次に 2D用の行列として 2 x 3の行列を作ります(3 x 3でもいいのですが面倒なのでこれで)。
画像の中心の画面上の表示位置 [posX, posY]もこの段階で入れてきます。
[color=#d0d0ff" face="monospace]
float m[3][2] = { { 1, 0 }, { 0, 1 }, { posX, posY }, };
[/color]
次にスケーリングです。値をそれぞれ scaleX、scaleYとするなら
[color=#d0d0ff" face="monospace]
m[0][0] *= scaleX; m[0][1] *= scaleX;
m[1][0] *= scaleY; m[1][1] *= scaleY;
[/color]
とします。
最後に回転を行います。
角度(ラジアン)を angleに入れておけば
[color=#d0d0ff" face="monospace]
float cos_val = std::cosf(angle);
float sin_val = -std::sinf(angle);
float tm0 = cos_val * m[0][0] + sin_val * m[1][0];
float tm1 = cos_val * m[0][1] + sin_val * m[1][1];
float tm2 = -sin_val * m[0][0] + cos_val * m[1][0];
float tm3 = -sin_val * m[0][1] + cos_val * m[1][1];
m[0][0] = tm0; m[0][1] = tm1; m[1][0] = tm2; m[1][1] = tm3;
[/color]
という計算になります。
これで必要な移動・回転・スケーリングを行う行列は完成です。
あとは、先に求めた4頂点に対してこの行列を適用していきます。
[color=#d0d0ff" face="monospace]
for(int n=0; n<4; ++n)
{
float x = pos[n].x * m[0][0] + pos[n].y * m[1][0] + m[2][0];
float y = pos[n].x * m[0][1] + pos[n].y * m[1][1] + m[2][1];
pos[n].x = x;
pos[n].y = y;
}
[/color]
配列 posに表示に必要な4つの頂点が入りましたので、これをそのまま
描画ライブラリに入れればOKです。
指定したスケーリングを画面に対して維持したまま回転してくれます。
慣れないと結構難しいと思いますが、環境によっては行列のサポートライブラリが
ありますので、そちらを利用するのがいいかと思います。
環境が不明瞭なので一般的に話になりますが、DirectXや OpenGLなど大抵の場合
4頂点を指定してトライアングルストリップかトライアングルファンを
表示する機能がありますので、それを使うことになります。
で行列計算を使って表示する4点の座標を求めて、その4頂点描画機能を使って
表示するのが一番いいですね。
ここから先は行列がわからないとちょっとつらいかもしれません。
座標変換
ttp://www.geocities.co.jp/SiliconValley-Bay/4543/Rubic/Mathematics/Mathematics-2.html
ttp://www.mech.tohoku-gakuin.ac.jp/rde/contents/course/robotics/coordtrans.html
ttp://nis-lab.is.s.u-tokyo.ac.jp/nis/CG/cgtxt/cg2/cg024.htm
まず、画像の中心座標を原点としたときの回転・スケーリングしていないときの
4点の座標を出します。
これは縦横の画像サイズがわかっていれば出せます。
画像サイズがそれぞれ imageSizeX、imageSizeYだとすると
[color=#d0d0ff" face="monospace]
struct position
{
float x, y;
};
position pos[/url] =
{
{ - imageSizeX/2, - imageSizeY/2 },
{ + imageSizeX/2, - imageSizeY/2 },
{ + imageSizeX/2, + imageSizeY/2 },
{ - imageSizeX/2, + imageSizeY/2 },
};
[/color]
となります。
次に 2D用の行列として 2 x 3の行列を作ります(3 x 3でもいいのですが面倒なのでこれで)。
画像の中心の画面上の表示位置 [posX, posY]もこの段階で入れてきます。
[color=#d0d0ff" face="monospace]
float m[3][2] = { { 1, 0 }, { 0, 1 }, { posX, posY }, };
[/color]
次にスケーリングです。値をそれぞれ scaleX、scaleYとするなら
[color=#d0d0ff" face="monospace]
m[0][0] *= scaleX; m[0][1] *= scaleX;
m[1][0] *= scaleY; m[1][1] *= scaleY;
[/color]
とします。
最後に回転を行います。
角度(ラジアン)を angleに入れておけば
[color=#d0d0ff" face="monospace]
float cos_val = std::cosf(angle);
float sin_val = -std::sinf(angle);
float tm0 = cos_val * m[0][0] + sin_val * m[1][0];
float tm1 = cos_val * m[0][1] + sin_val * m[1][1];
float tm2 = -sin_val * m[0][0] + cos_val * m[1][0];
float tm3 = -sin_val * m[0][1] + cos_val * m[1][1];
m[0][0] = tm0; m[0][1] = tm1; m[1][0] = tm2; m[1][1] = tm3;
[/color]
という計算になります。
これで必要な移動・回転・スケーリングを行う行列は完成です。
あとは、先に求めた4頂点に対してこの行列を適用していきます。
[color=#d0d0ff" face="monospace]
for(int n=0; n<4; ++n)
{
float x = pos[n].x * m[0][0] + pos[n].y * m[1][0] + m[2][0];
float y = pos[n].x * m[0][1] + pos[n].y * m[1][1] + m[2][1];
pos[n].x = x;
pos[n].y = y;
}
[/color]
配列 posに表示に必要な4つの頂点が入りましたので、これをそのまま
描画ライブラリに入れればOKです。
指定したスケーリングを画面に対して維持したまま回転してくれます。
慣れないと結構難しいと思いますが、環境によっては行列のサポートライブラリが
ありますので、そちらを利用するのがいいかと思います。
Re:画像の擬似3D表示について
であれば、こちらが参考になるかと。
回転描写と拡大縮小描写
ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=1033
回転描写と拡大縮小描写
ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=1033
Re:画像の擬似3D表示について
おお!すでに同じ質問をしてる人がいたか・・・
>ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=1033
このページにかいてある
DrawModiGraphF()
ってのは龍神録プログラミングの館にでてくるものでいいんですよね?
>ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=1033
このページにかいてある
DrawModiGraphF()
ってのは龍神録プログラミングの館にでてくるものでいいんですよね?
Re:画像の擬似3D表示について
おお、できました!
これは縦、横を潰して回転描写できるんですね。
これみたらまた疑問が・・・
画像使いますねw
画像の上が今回の画像描写
では、下のように描写する場合は画像の頂点A、Cを潰し、B、Dを伸ばせばいいわけですよね?
こういうこともできるんでしょうか?
また回転は時計回りですが、反時計回りもできるんでしょうか?
これは縦、横を潰して回転描写できるんですね。
これみたらまた疑問が・・・
画像使いますねw
画像の上が今回の画像描写
では、下のように描写する場合は画像の頂点A、Cを潰し、B、Dを伸ばせばいいわけですよね?
こういうこともできるんでしょうか?
また回転は時計回りですが、反時計回りもできるんでしょうか?
Re:画像の擬似3D表示について
>こういうこともできるんでしょうか?
可能です。
DXライブラリを用いた例だとその図の上のようにするには
「回転(毎フレーム変化する) -> スケール -> 移動」という順番で行っていましたが。
下の図のようにするには
「回転(毎フレーム変化する) -> スケール -> 回転2 -> 移動」という順番で行列を
掛けて合わせてください。
この回転2のところに、一定の角度(図と同じにするなら -π/4の角度)の行列を与えることで
下の図のように傾いて潰れた回転ができるはずです。
>反時計回りもできるんでしょうか?
できます。
毎フレーム変化する角度の差分の符号を反転させるだけです。