みなさん、こんにちは。
今回で、C#でOpenGLを使う方法についての紹介は最後になります。
(※よりテクニカルな話題を、突発的に紹介することがあるかもしれませんが…)
前回は座標変換行列について話しました。
今回は、座標変換をOpenTKで実現する方法についてお話します。
それでは、前回話しました座標変換行列をOpenTKで書いてみましょう。
ワールド座標系→ビュー座標系→射影座標系→スクリーン座標系までの変換は、OpenTK.Matrix4 クラスの機能を使えば簡単に求められます。
ちなみに、この一連の変換を行う関数を、CalculateWorldToScreenと名付けましょう。
関数の引数には、カメラの視点/注視点/上ベクトル/near/far(それぞれワールド座標系での値)、カメラの縦方向の視野角(ラジアン単位)、スクリーン座標系での幅と高さ(ピクセル単位)を取ります。
ワールド座標系からカメラ座標系への変換行列は、OpenTK.Matrix4.LookAt関数を使って計算できます。
また、カメラ座標系から射影座標系への変換行列は、OpenTK.Matrix4.CreatePerspectiveFieldOfView関数を使って計算できます。
射影座標系からスクリーン座標系への変換(=ビューポート変換)は、自分で計算します。
射影座標変換後の立方体をX-Y平面から見ると、図の左のようになります。
左上の座標が(-1.0, 1.0) に、右下が(+1.0, -1.0)ですが、スクリーン座標変換をすると左上が(0, 0)に、右下が(w, h)になるような変換を行います。
※図は OpenGLのglViewPort関数のもので、スクリーン座標変換後の+h方向の向きが上になっていますが、+h方向が下向きになるようにしてください。
すると、変換後の x = width / 2 × (変換前の x + 1)、変換後の y = height / 2 × (-変換前の y + 1) となります。
もし座標変換をシェーダに任せたい場合は、スクリーン座標変換を除いた座標変換行列を、GLSLのシェーダ定数にそれぞれセットする形で行います。
スクリーン座標変換は、CPU側で OpenTK.Graphics.GL.Viewport(0, 0, OpenTK.glControl.Width, OpenTK.glControl.Height); を呼んでやればよいです。
余談ですが、上記一連の流れの逆行列を作れば、スクリーン座標系のピクセル値からワールド座標系の3次元の座標を求めることもできます(※後日談でお話しするかもしれません)。
いかがでしたしょうか?
今後も3DCG関連でお話することがありましたら、発信していきたいと思います。