スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

カーソルで3次元上のモデルを指す 方法!

今日は、
クライアント座標から3次元上の物体を指すプログラム
を作って見ました。

まず結果から。

【参考画像】
当たり判定2

小さい白い四角がカーソルだと思ってください。
また、 四角ポリゴンが描画されている所に入ると、カラフルになるようになってます。

そして、上記の画像を見ても分かるように、
ちゃんと当たり判定が行われている事がわかると思います。

上記の画像は、単純に単位行列で表示しているだけですが、
もちろん、ポリゴンを回転させるなどの処理を行っても正常に判定してくれます。
↓この通り

【参考画像】
当たり判定

で、今回は
------------------------------------------------------------------------------------
クライアント座標から3次元上の座標へ変換し、
更に 物体をクリックしているのか否かを調べる方法

------------------------------------------------------------------------------------
を解説してみようと思います。



やり方
----------------------------------------------------------------------------------
【1】3次元上の座標に変換する行列を求める。
【2】求めた行列で、カーソル位置の座標を変換。(点p,qとする)
【3】線分pqがポリゴンを貫通する点を求める。
【4】求めた点が、ポリゴンの内部にあるかどうかを判定。

----------------------------------------------------------------------------------


【1】3次元上の座標に変換する行列を求める。
これは以前 述べましたが、
3次元上の点は下記の様に行列で変換されています。

頂点A × ワールド変換行列 × ビュー行列 × 射影変換行列 × ビューポート行列 = 変換後の頂点A

なので、元に戻す場合は 逆行列を右から順にかけていけば元に戻せます。
頂点A = 変換後の頂点A × ビューポート行列 × 射影変換行列 × ビュー行列 × ワールド行列


逆行列の求め方は、本当に面倒くさいのですが、
(楽に求められるのは2×2の行列ぐらいまでかと)
幸い逆行列を算出してくれるヘルパー関数があるので、今回はそれを使います。
D3DXMatrixInverse関数です。

↓使い方はこんな感じになります。
--------------------------------------------------------------
D3DXMatrixInverse(&i_port, NULL, &g_port);
D3DXMatrixInverse(&i_view, NULL, &g_view);
D3DXMatrixInverse(&i_proj, NULL, &g_proj);

--------------------------------------------------------------
※第一引数は、算出された逆行列を格納する変数を指定
第二引数は、通常はNULLでOK
第三引数は、逆行列を求めたい行列を指定します。


【2】求めた行列で、カーソル位置の座標を変換。
(点p,qとする)


3Dのモデルは、2次元のウィンドウに描画されるわけですが、
実はこのときのz座標は0.0f~1.0fの範囲になってます。
(0.0fが一番手前、 1.0fが一番奥)

で、カーソルの位置が(160, 80)だったとします。
この時2つのD3DXVECTOR3型の変数を定義し、値をそれぞれ
----------------------------------------
(160, 80, 0.0f)  ※pとする
(160, 80, 1.0f)  ※qとする

----------------------------------------
にします。

この2つのベクトルを先ほど求めた逆行列で変換するとどうなるか?というと
それぞれ3次元空間上での一番手前と一番奥の点になります。

つまり、この2つの点p,qを結んで出来る線分pqは、
途中にポリゴンなんかがあれば必ず貫通する事になります。

【参考画像】
当たり判定3

【3】線分pqがポリゴンを貫通する点を求める。
これから線分pqがポリゴンを貫通しているか?を調べて行く訳ですが、
まずポリゴンと同一平面上にある点を求めます。

で、なんで同一平面状じゃないといけないのか?と言うと、
同一平面上じゃないと貫通しているのかが分からないからです。

例えば、下記の画像をご覧下さい。

【参考画像】
当たり判定4

x軸上に青いポリゴンがあり、そして点pqがあります。
また、青いポリゴンは(1, 0) ~ (7, 0)の範囲にあるとします。

この場合、点pのx座標が1~7の間にあるとしても、
線分pqが真っ直ぐな線でなければ貫通しない場合が出てきます。

次に、同一平面上の点rを求めたとします。
(今回は、 同一平面上 = x軸上)

この場合は、線分pqがどんな傾きであろうと、
点rがポリゴンの内部にあれば確実に貫通していると断言できるのです。
(逆に、ポリゴン外部にあれば確実に貫通していない。)

【参考画像】
当たり判定5


という訳で、
まずは何としても同一平面上の点を求めなければならないのです。
で、求め方がコレ。 ↓
-------------------------------------------------------------------------
【1】ポリゴン上の任意の点vを選ぶ。
【2】ポリゴン上の点vから、点pqを結ぶベクトルを求める。
【3】点p,qから、ポリゴンと同一平面上の面までの距離をそれぞれ求める。
【4】点vから、距離の比率をかけたベクトルvpとvqを足す。

-------------------------------------------------------------------------
【参考URL】gameつくろー! 線分と板ポリゴン
※↑こちらを参考にしました

実際にやってみます。
下記の図と一緒に見てみましょう。

【参考画像】
当たり判定6

まず、【1】のようにポリゴンと点p,qがあるとします。
(正直、図を見れば貫通点rは分かるのですが、分からないものとします。

で、任意の点vを選び、その点vから点p,qまでのベクトルを求めます。(【2】)
vp = (-2 2 0) - (0 2 0)  ← p - v
vq = ( 2-2 0) - (0 2 0)  ← q - v
vp = (-2 0 0)
vq = ( 2-4 0)


次に、ポリゴンと同一平面上の面からの距離を求めます。
※同一平面上、というのはポリゴンを無限に引き伸ばしたものと考えてください。
この例では、y軸 = 同一平面上 になります。

距離は、ポリゴンの法線ベクトルとの内積で求められます。
3次元のベクトルA,Bの内積の計算の仕方は、下記の通りです。
----------------------------------------------------------------
Ax×Bx + Ay×Ay + Az×Bz
----------------------------------------------------------------
(要するに、各要素をかければOK)

とりあえず、ポリゴンの法線ベクトルを(1 0 0)とします。
vp = (-2 0 0)
vq = ( 2-4 0)
n = (1 0 0)

Dot(n, vp)
= -2*1 + 0*0 + 0*0
= -2

Dot(n, vq)
=2*1 + -4*0 + 0*0
= 2


そして、距離なのでマイナスの符号を消します。 (絶対値をとる)
すると両方とも距離が2である事が分かると思います。
上記画像を見ても確認できますね。

-----------------------------------------------------------------
※法線ベクトルは正規化しておいてください。(大きさを1にする)
例えば法線ベクトルが(100 0 0)だとすると、正規化して(1 0 0)にしておかないと、
同一平面上までの距離が200という、意味の分からん答えになります。
-----------------------------------------------------------------

で、最後の【4】。
まずvpとvqの距離の比率を求めます。
vpとvqは両方とも2なので、 比率は1:1です。

高校の数学の内容になるのですが、線分pqをa:1-aに内分する点rがあった場合、
v+(1-a)×vp + a×vpで点rの座標を求められるのです。

【参考画像】
当たり判定7

今回は1:1なので
------------------------------------
a = 1 /(1 + 1)
a = 0.5

------------------------------------
vの座標に、vpとvqに0.5をかけて足せば貫通点rが出せます。
(2つ前の画像参照)


【4】求めた点が、ポリゴンの内部にあるかどうかを判定。
同一平面上の点が出たので、後はその点がポリゴンに含まれているかどうか
調べます。

これは外積を使えばOKです。


※3次元の外積について※
3次元のベクトルA,Bがあった場合、その2つのベクトルの外積をとると
ベクトルA,B両方に垂直なベクトルが求まるという
性質があります。

計算方法↓
(Ay*Bz-Az*By, Az*Bx-Ax*Bz, Ax*By-Ay*Bx)

例えば、 x軸(1 0 0)とz軸(0 0 1)の外積を求めるとします。
この場合、 (0*1 - 1*0, 0*0 - 1*1, 1*0 - 0*0)となり、

最終的に(0 -1 0)となります。
これは、(正負の違いはありますが)y軸座標のベクトルと同じですね。

y軸は、x軸とz軸に対して垂直なので、
外積をとった両方のベクトルに垂直なベクトルが出た事になります。

で、この垂直なベクトルと言うのは、ポリゴン上の2つのベクトルの外積をとった場合、
ポリゴンの法線ベクトルになります。

逆に、ポリゴン外部にある点と外積をとった場合、
法線と間逆のベクトルになります。

なので、外積が法線のベクトルと同じなのかを調べれば、
貫通点がポリゴン内部にあるのかどうかを調べられます。

【参考URL】ポリゴン上に点が含まれるかを判定

【ソースコード】Sample_Intersect.txt
スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント
コメントの投稿
管理者にだけ表示を許可する



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。