WebGLスクール第1回参加メモと復習

WebGLを本格的に始めようと思い、WebGLスクールに通うことにしました。体験回を除くと全5回(隔週土曜日、一回5時間)のスクールで、5/30に1回目を受けてきたので、内容整理として文章を書いています。
http://webgl.souhonzan.org/entry/?v=0203

体験回行ったときのメモはこちら

今回の学習範囲でつくってみたもの

スクール第1回の復習として、習った内容を使ってちょっとしたアニメーションを作成しました。下の「start」ボタンを押すと始まります。(ボタン連打すると遅くなるかも)

頂点を8つ配置し、立方体を描画。それをフレームごとに回転、拡大縮小させています。カメラ座標は固定なので、マウス位置を取得してカメラ座標に入れ込めば、若干インタラクティブにできそうなのでそれを模索中。あと、描写されない想定の青い線がなぜか描写されてしまっているので、その謎を解明すべく探索中。

習ったこと

スクールの第1回(体験回を入れると第2回)のテーマは「WebGL に欠かせない概念を理解しよう!」。
主に以下の内容を勉強しました。(詳しい内容は講師の方が運営しているwgld.orgを見た方がいいと思います)

  • レンダリングまでの流れ(レンダリングパイプライン)
  • 頂点シェーダとフラグメントシェーダ
  • ライブラリ(glcubic.js)
  • 頂点バッファ(VBO)とインデックスバッファ(IBO)
  • プログラムオブジェクト
  • 座標変換行列(モデル変換行列、ビュー変換行列、プロジェクション変換行列)

以下、自分用の整理です。

レンダリングまでの流れ(レンダリングパイプライン)

レンダリングパイプラインとは、入力された頂点データを2次元のディスプレイに表示するまでの一連の流れのことです。昔は頂点データや3Dモデルデータを入力するとあとは何の設定もいらずにレンダリングしてくれてたらしいです。ですが、より柔軟なレンダリングを行うためにレンダリングパイプラインの一部を開発者側で実装できるようになったのが、プログラマブルシェーダと呼ばれるもの。これはOpenGLDirectXなど、使用するAPIによって異なるらしいですが、WebGLでは開発者側で実装できる部分を2つ用意しており、それが頂点シェーダとフラグメントシェーダです。

頂点シェーダとフラグメントシェーダ

WebGLレンダリングパイプラインのなかで開発者側で実装できる部分が「頂点シェーダ」と「フラグメントシェーダ」。大雑把に言うと、頂点データをもとにして描画範囲を決めるのが頂点シェーダ、頂点シェーダで決められた描画範囲の1ピクセルごとにどの色で描画するのかを決めるのがフラグメントシェーダです。
したがって、WebGLのおおまかな描画の流れは以下のようになります。

  1. Javascriptで、3D座標上に頂点を配置。
  2. Javascriptで配置した頂点データを頂点シェーダに引き渡し、画面上のどこを描写するかの描写範囲を決定する。
  3. 頂点シェーダで決定した描写範囲をフラグメントシェーダに引き渡し。
  4. 描写範囲に含まれるピクセル1つ1つに対して、どの色で描写するかをフラグメントシェーダで決定する。
  5. その後色々経て、ディスプレイに出力。

この時、②で行われる「Javascriptで配置した頂点データを頂点データに引き渡す」ときに登場するのが頂点バッファ(VBO)とプログラムオブジェクトです。

頂点バッファ(VBO)とインデックスバッファ(IBO)

頂点シェーダに送る頂点データを作る際、配列で頂点座標を表現します。その配列データを頂点バッファ(Vertical Buffer Object = VBO)に格納することで、頂点シェーダに送る準備ができるようです。

また、webGLでは三角形をつくることで面の描写を行うため、たとえば正方形を描きたいと思ったときも直角三角形を2つ並べて表現することになります。三角形一つにつき頂点が3つあるため、普通であれば全部で頂点は6つ必要になるのですが、四角形一つにつき頂点6つはかなり無駄があります。そのため、頂点は4つだけ定義しておき、そのうちのどれを使って三角形を形成するか、を後から定義する方法があります。その後から定義したデータを入れるバッファがインデックスバッファ(Index Buffer Object = IBO)です。

プログラムオブジェクト

頂点バッファに入った頂点データをシェーダに引き渡すためのオブジェクトがプログラムオブジェクト。このオブジェクトに「引き渡される先の頂点シェーダ」「フラグメントシェーダ」「VBOとして引き渡される頂点データ」「頂点データ1つ1つの要素数」「座標変換行列」「引き渡すデータ名(?ちょっとここ曖昧)」を投げ込むと、シェーダと頂点データの連結がなされます。
ぶっちゃけこのあたりの理解がいまいちなので要整理。

座標変換行列(モデル変換行列、ビュー変換行列、プロジェクション変換行列)

たとえば頂点の座標を移動する。物体の角度を変える。カメラ位置を移動する。といった作業を行う場合、それぞれの作業を頂点一つ一つに対して行うのは非常に面倒です。そこで、行列を用いて座標を変えることでそれを効率的に行うのが座標変換行列。Javascriptで定義した頂点データ(VBOに入ってる)を変換して、3次元空間上の点にするのがモデル変換行列。カメラの位置を決めるのがビュー変換行列、カメラの視野角やカメラからの距離など、どの範囲を描写するのかを決めるのがプロジェクション変換行列。
これらの行列を各頂点に掛け合わせることで、レンダリングされる頂点が決定します。

課題点

1回目の講義を通して、以下の課題点を改めて実感しました。

Javascript自体の知識が少ない

オブジェクトの考え方や関数の引き出しなど、Javascript自体の知識の少なさのせいで、WebGLの理解も浅くなってしまう。Javascriptの基本的なところを勉強し直さないと講義に追いついていけないかもしれないです。そこらへんができてないとインタラクティブなものをつくるのも一苦労です。

ライブラリ(glcubic.js)の理解が足りない

WebGLの基本を押さえる、という理由で、このスクールでは鉄板ライブラリのthree.jsを使わない方針をとっているようです。(WebGLjQueryみたいなイメージ)
とはいえどうしても記述が煩雑になってしまう計算式などは丸めて効率化してしまおう、という意図で講師の方が作られたライブラリがglcubic.jsなのですが、この中身を読み解いていく作業がなかなか難航しています。特にプログラムオブジェクト付近。これはある程度復習で読み解く必要がありそう。

とはいえ、まだ全5回の第1回が終わったところなので、じっくり取り組んでいきたいと思います。