読者です 読者をやめる 読者になる 読者になる

おはよう君需要なし

求不得苦な日々

C#でOpenGLを使ったプログラミング「とりあえず回転」

はじめに

 さて、3Dグラフィックを3Dグラフィックたらしめるものって何でしょう。それは「回転」です。

 自分的にはそう考えているんですが、これには以下の理由があります。

  • 三次元空間には前後関係がある
  • 平行移動=拡大・縮小(二次元の域を脱しない)

みたいな???まぁ、2つ目は2つの物体の前後関係が変わるような平行移動を行えば 「あ~~~これは三次元グラフィックっぽい」ってなるかもしれませんが、一目瞭然「おお三次元グラフィック!」ってなるのは やっぱ物体が回転しているところを見ることでしょう。(無理やり)

回転方法

 まず、物体の回転方法について考えて見ましょう。ユーザの入力に対してどう動かすのかというのはユーザインタフェースを作るうえでは超重要なことですよね。

 ぼくが調べていて一番よく見かけるのが「x軸周りの回転角とy軸周りの回転角用の変数を準備してモデルを回す」という方法。

  • マウスがx方向に動いたらy軸周りに回転
  • マウスがy方向に動いたらx軸周りに回転

一見、こちらの方法で物体を回転させれば、一応全方向眺められることになりますよね。すごく無難に見えます。

というわけで作ってみた

 まずはマウス入力のところから。コントロールのOnMouseMoveをオーバーライドし、m_bIsMouseDown変数がTrueの時のみm_thetaY,m_thetaXを増減させます。 m_thetaX,m_thetaYについては言うまでもなくx軸周りの回転角とy軸周りの回転角を保持するfloat型変数です。

float rotate_speed = 0.5f;
protected override void OnMouseDown(OpenTK.Input.MouseButtonEventArgs e)
{
    base.OnMouseDown(e);
    this.m_bIsMouseDown = true;
}
protected override void OnMouseUp(OpenTK.Input.MouseButtonEventArgs e)
{
    base.OnMouseUp(e);
    this.m_bIsMouseDown = false;
}
protected override void OnMouseMove(OpenTK.Input.MouseMoveEventArgs e)
{
    base.OnMouseMove(e);
    if (m_bIsMouseDown)
    {
        m_thetaY += rotate_speed * e.XDelta;
        m_thetaX += rotate_speed * e.YDelta;
    }
}

で、これで増減された結果を以下のコードのように表示の直前でRotateさせてあげます。

    GL.Rotate(m_thetaX, Vector3d.UnitX);
    GL.Rotate(m_thetaY, -Vector3d.UnitY);

    drawAxis();

drawAxis関数は軸を描画するための関数です。

結果

f:id:yoh_mar28:20150503005343p:plain

ばばーん!!自由にマウスで動かすことができるようになったぞ!!!!!!!!

自由に・・・だと!?

 はい、こちらのコードを実際にコーディングしてもらって実行してもらえばわかるんですけど、この方式だと全然自由じゃないf:id:yoh_mar28:20150503005500p:plain

どんなに頑張ってもy軸(赤い矢印)の先が上下にしか動かない!!!

 それもそのはず。だって上のソースコードじゃx軸周りに回転させてから、(回転させた後の座標系で)y軸周りに回転させるようになっているんだもの。

 「ではy軸回転を先に持ってくれば解決するか」といったらそうでもない。今度はx軸の先が左右にしか動かなくなってしまいます。

 ビューアとはもっと縦横無尽にモデルを動かして見られるものであるべきですよね。こんな拘束があるビューアなんてあんまりだゼッ!!