C#でツールを作る その8 -カメラの制御-

3Dのツールなので、マウスのドラッグ・ホイールによるカメラの制御は必須です。
ということで、以下の機能を追加します。

  • 右ドラック:カメラの回転
  • ホイール:ズーム


サンプル

極座標

カメラの回転の実装方法はいろいろありますが、今回は極座標で求めます。

wikiの解説とDirect3Dの軸の向きは異なるので、無理やり合わせます。

  • 赤:X(wikiではX)
  • 緑:Y(wikiではZ)
  • 青:Z(wikiではY)
float X = ( float )( r * Math.Sin( theta ) * Math.Cos( phi ) );
float Y = ( float )( r * Math.Cos( theta ) );
float Z = ( float )( r * Math.Sin( theta ) * Math.Sin( phi ) );

View(UserControl1)にマウスのイベントハンドラを追加

  • アプリケーションのコンストラクタでMouseMoveイベント、MouseWheelイベントを追加
  • 北極、南極付近でジンバルロックが起こらないよう調整
    • θを0°以下、180°以上にしない
  • とりあえずズームの増加量は適当
private Point prev_mouse;
private float theta = 45.0f;
private float phi = -45.0f;
private float zoom = 45.0f;

public Hoge()
{
    view = new UserControl1();
    view.Paint += new PaintEventHandler( Paint );
    view.MouseMove += new MouseEventHandler( view_MouseMove );
    view.MouseWheel += new MouseEventHandler( view_MouseWheel );

    MainForm = new Form1( view );
    MainForm.Disposed += new EventHandler( ReleaseDevice );
}

private void view_MouseMove( object sender, MouseEventArgs e )
{
    if( e.Button == MouseButtons.Right )
    {
        float x = ( float )( e.Location.X - prev_mouse.X ) * 1.0f;
        float y = ( float )( e.Location.Y - prev_mouse.Y ) * 1.0f;
        phi -= x;
        theta -= y;
        if( theta >= 180.0f )
        {
            theta = 179.99f;
        }
        if( theta <= 0.0f )
        {
            theta = 0.01f;
        }

        view.Refresh();
    }
    prev_mouse = e.Location;
}

private void view_MouseWheel( object sender, MouseEventArgs e )
{
    zoom -= e.Delta / 120.0f * 3;
    if( zoom < 0.0f )zoom = 1.0f;
    if( zoom > 180.0f )zoom = 179.0f;

    view.Refresh();
}

ビュー行列の設定

  • degreeからradianへの変換
    • Geometry.DegreeToRadian
float r = 5.0f;                             //半径
float t = Geometry.DegreeToRadian( theta );
float p = Geometry.DegreeToRadian( phi );
Vector3 v = Vector3.Empty;
v.X = ( float )( r * Math.Sin( t ) * Math.Cos( p ) );
v.Y = ( float )( r * Math.Cos( t ) );
v.Z = ( float )( r * Math.Sin( t ) * Math.Sin( p ) );

device.Transform.View = Matrix.LookAtLH(
    v,       //カメラ座標
    new Vector3( 0.0f, 0.0f, 0.0f ),        //注視点
    new Vector3( 0.0f, 1.0f, 0.0f )         //カメラの真上方向
    );