WebGLで書いてみよう

firefoxの地雷版Minefieldでは、WebGLが使えます。

WebGLを使うにはまず、about:configで"webgl.enabled_for_all_sites"を"true"にします。
また、グラボがなく945など古めのintelオンボードグラフィックスを使ったPCの場合、osmesa32.dllをダウンロードし、そのPATHを"webgl.osmesalib"に書く必要があるでしょう(例: "C:\programs\osmesa\OSMESA32.dll")。

これでHTMLにアクセスすれば、WebGLなプログラムが実行できるようになります。

OpenGL ESとかGLSLとか実際に使ったことが無かったので、手探りでどういう風に使えばいいかを試しながら書いたのが以下のコードです。1ファイル完結でライブラリ等は使用していません(ベクトル処理は自作している)。

一応、textareaにシェーダーコードを書いてあり、書き換えできるようにはしてます。

感想

  • GLSLのどのバージョンが使えるのか悩んだ(結局1.10らしい)
  • WebにあるGLSLのチュートリアルの多くが互換プロファイル(もともとのOpenGLがもってたvertex, normal, lighting等に相当する変数)の構造を使っていて、WebGLではそれが使えず役に立たない
  • OSMESA環境とGeForce環境とで使える関数が違うようだ... (gl.clearDepthfはGeForceなら使えている)
  • シェーダープログラム中の変数のtraceみたいなことはしたい気がするがどうすればいい?
  • drawArraysで使えるのはTRIANGLESのみ(QUADSはないようだ)
  • topスコープに突然CanvasFloatArrayがあるのが気にはなる
  • OpenGLのmatrixの配列レイアウトとか、座標系とか混乱する
  • もともとのOpenGL APIからはだいぶ減ったが、gl.vertexAttribPointer前後のステートフルさはあまり好きじゃない

WebGLやGLSLとは

WebGLの場合、Vertex Shaderでgl_Positionを、Fragment Shaderでgl_FragColorをセットすることで、図形を画面に出してくれるようです。

  • gl_Positionは図形の頂点です。vec4で、(x, y, z, w)とすると、x/w, y/w, z/wが -1.0〜1.0の間にある頂点が表示されます。z/wは深さで、1.0が一番手前で、それより後ろは隠れます。スクリーン上の点は(x/w,y/w)で、canvasの中央が(0,0)で右上端が(1.0, 1.0)です。
  • gl_FragColorは塗りつぶす色です。vec4で、それぞれ0.0〜1.0のRGBAのようです。

vertex shaderがdrawArraysによって、その引数の数ぶんの頂点を処理し、その結果から深さ判定や線形補完を行って、対象となる表示画面上のピクセルごとにfragment shaderが処理されます。

これらshaderには外部からセットされる変数があります。

  • uniform変数は、shader program上にセットできる固定値です。
  • attribute変数は、vertex shaderでは、drawArraysの引数の数ぶんに分けられて、わたってくる値です。
  • varying変数はvertex shaderでセットします。fragment shaderの同名のvarying変数は、gl_Positionに応じて線形補間された値に変換されて入りるようです。


基本、親コード上では、

  • ソースコードコンパイルして作ったvertex shaderとfragment shaderを入れたshader programを作る
  • そのvertex shader program中にあるuniformやattributeといった変数に(頂点バッファなどの)値をセットする
  • gl.drawArraysを呼ぶ

ことで、画面に絵を書いてくれるようです。

コード