C#でツールを作る その14 -スクリーン座標をワールド座標に変換-
数学は苦手です!
数式だけ書かれてもわかりませんっ!!
図を描いて下さい。
とりあえず、スクリーン座標p(x,y)のワールド座標q(x',y',z')を求めます。
逆行列による2Dから3Dへの逆変換
カメラと被写体の間に3Dのスクリーンがあると考え、その平面上の点qを求めます。
といっても、pにワールド、ビュー、プロジェクション、ビューポートの逆行列を掛けるだけです。
さらに言うと、Direct3Dで2D→3D逆変換のための関数が用意されています。
public struct Vector3{ public static Vector3 Unproject(Vector3 v, object viewport, Matrix projection, Matrix view, Matrix world); }
-
- ビューポートは行列ではない
- ワールドは単位行列でよい
- 変換元のスクリーン座標pのZ座標は0〜1(プロジェクションのznearPlane〜zfarPlaneを表す)で指定
private Vector3 ScreenToWorld( Point p ) { return Vector3.Unproject( new Vector3( p.X, p.Y, 0.0f ),//naerPlane上 device.Viewport, device.Transform.Projection, device.Transform.View, Matrix.Identity ); }
平面と線分の交点を求める
ベクトルと平面ax+by+cz+d=0から数学的に求めることも出来ますが、もちろんこれも関数が用意されています。
public struct Plane { public static Vector3 IntersectLine(Plane p, Vector3 v1, Vector3 v2); }
- 平面、線分の始点、終点を渡す
private Vector3 ToZXPlane( Vector3 v ) { Vector3 ret; if( camera_pos.Y - v.Y != 0.0f ) { Plane plane = new Plane( 0.0f, 1.0f, 0.0f, 0.0f );//ZX平面 ret = Plane.IntersectLine( plane, camera_pos, v ); ret.Y = 0.0f; } else { //視線とZX平面が交差しない場合はfarPlaneを使用 Plane plane = new Plane( 0.0f, 0.0f, -1.0f, 100.0f );//zfarPlane ret = Plane.IntersectLine( plane, camera_pos, v ); } return ret; }
3Dではベクトル、行列、平面、クォータニオンが必須なので、もう少し復習していきます。。。