lesson1を学んだ。順にそれぞれ自分の理解をメモしながらまとめる。
PyCGでは全編を通して以下の2つのケースを学ぶ。
- 液体の表面をアニメーションさせるための偏微分方程式を解くデモ
- 球体の表面上に画像を描画するインタラクティブなプログラム
OpenGLに関する素晴らしいチュートリアル(learnopengl など)が多数あり、PythonとC++の関数呼び出しはほぼ同じである。このチュートリアルでは、実世界の問題を効果的に解決するために、PythonからOpenGLをどのように使うかに焦点を当てる。
必須のパッケージ
全体を通して使用する重要なパッケージは2つある。PyOpenGLは基本的なOpenGLの機能にアクセスすることを可能にし、glfwは複数のプラットフォーム上でウィンドウを作成したり、イベントを処理したりすることを可能にする。
PyOpenGL
OpenGLと関連APIへの最も一般的なPythonバインディング。バインディングは標準の ctypes ライブラリを使って作成され、BSD スタイルのOSS。PyOpenGL_accelerate は、実行速度の高速化が目的。
本ブログでも、他のサンプルでも紹介した通り環境構築を説明している。
glfw
GLFWのPythonバインディング。オリジナルのGLFW APIに非常に近い状態を保つctypesラッパー。(システムに glfw3 がインストールされている必要がある)。
OpenGL座標系
OpenGLは正規化デバイス座標(NDC)で、x、y、z軸の値の範囲が[-1,1]以内であることを規定している。この範囲外のものは見えない。また、OpenGLの3D座標系は、Z軸の正の方向が画面から外に向いている。(learnopenglの座標系の詳しい説明)
OpenGL レンダリング パイプライン
OpenGLは、三角形を使って動作する。各三角形の領域は、ピクセルでラスタライズされ(これをフラグメントと呼ぶ)、色を割り当てる。
これらのプロシージャは、カスタマイズされたプログラム(シェーダと呼ばれ、GLSLと呼ばれるCのような言語で書かれる)はGPUによって処理される。
グラフィックスパイプラインには以下の3種類のシェーダがある。
頂点シェーダ
個々の「頂点」を処理するレンダリングパイプライン内のプログラマブルシェーダの段階。
ジオメトリシェーダ
単一の点や三角形などのプリミティブを形成する頂点のセットを入力として受け取る。次のシェーダステージに送る前に、それらの頂点を適当に変換することができる。頂点を全く異なるプリミティブに変換することができ、最初に与えられたものよりもはるかに多くの頂点を生成することができる。
フラグメントシェーダ
ラスタライズによって生成されたフラグメントを、色のセットと単一の深度値に処理するシェーダステージ。フラグメントシェーダは、プリミティブがラスタライズされた後のOpenGLパイプラインの段階。プリミティブがカバーするピクセルの各サンプルに対して、「フラグメント」が生成される。
ジオメトリシェーダはオプションだが、頂点シェーダとフラグメントシェーダは、正しく動作するためには必要不可欠である。
こちらのページでは、頂点シェーダとフラグメントシェーダの書き方を簡単に紹介している。
ホストとデバイス間の通信
OpenGLは、GPU(デバイス)がCPU(ホスト)のメモリに直接アクセスできないアーキテクチャ(ヘテロジニアス)を想定している。そのためホストからデバイスにデータを渡すための特別なアプローチが必要となり、主に以下の2つの方法がある。
VBO(頂点バッファオブジェクト)とVAO(頂点属性オブジェクト)
この2つを組み合わせることで、配列をホストからデバイスに渡すことができる。配列は頂点に分割され、各頂点はそれ自体をレンダリングするために必要なすべてのデータを保持する。
Uniform
ホストからデバイスに単一のデータ要素を渡すことができる。例えば、整数、ベクトル、行列をUniform経由で渡すことができる。
Hello triangle!
最後に、次のようなウィンドウを生成する簡単なデモを紹介する。
Ubuntuでは、ウィンドウサイズを変更するまで真っ白に描画される。(window_resize_callbackが無効なパラメータで内部的に呼び出されているため)macOSでは問題なく動作する。windowsでも問題なく動作することを確認した。