まるまるこふこふ

数々の次元が崩壊し、全ての生命が塵と化すのを見てきた。私ほどの闇の心の持ち主でも、そこには何の喜びも無かった。

WebGL を利用して描画するまでの流れ

概要

WebGLを利用して描画する場合、描画までに実行する API のお約束が多い。

これは描画に必要なパラメータが膨大なため、 各API関数を呼び出して、グローバル変数である WebGL コンテクストの状態を変更していくことで、 描画に必要なパラメータを設定していく設計思想になっているためと思われる。

また WebGL の元となった OpenGLGPUハードウェアの制約の中で パフォーマンス向上のために API を追加し続けてきたため、 同じ描画を行う上でも、様々な方法がある(現在では推奨されないAPIもたくさん存在する)

流れ

  • GLContextの作成
var c = document.getElementById('canvas');
var gl = c.getContext('webgl');
  • シェーダーの生成

    • 頂点シェーダ
      • シェーダーの生成
        var shader = gl.createShader(gl.VERTEX_SHADER);

      • シェーダーにソースコードを割り当てる
        gl.shaderSource(shader, "shader source code");

      • シェーダーのソースコードコンパイル
        gl.compileShader(shader);

      • 正しくコンパイルできたことをチェック if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ alert(gl.getShaderInfoLog(shader)); }

    • フラグメントシェーダ
      • シェーダーの生成
        var shader = gl.createShader(gl.FRAGMENT_SHADER);
      • 以降は頂点シェーダーと同様
  • プログラムオブジェクトの生成
    プログラムオブジェクトは、各シェーダーをまとめたもの

    • プログラムオブジェクトの生成
      var program = gl.createProgram();

    • プログラムオブジェクトにコンパイルしたシェーダを割り当てる
      gl.attachShader(program, vs); gl.attachShader(program, fs);

    • シェーダをリンク
      gl.linkProgram(program);

    • シェーダのリンクが正しく行なわれたかチェック
      if(!gl.getProgramParameter(program, gl.LINK_STATUS)){ alert(gl.getProgramInfoLog(program)); }

    • プログラムオブジェクトを有効にする
      gl.useProgram(program);
  • 頂点バッファを作る
    VBOやIBOが毎フレームごとに変更される場合は、描画の際に頂点バッファを作る必要がある

    • Vertex Buffer Object(VBO)

      • バッファオブジェクトの生成
        var vbo = gl.createBuffer();
      • バッファをバインドする バッファに値を設定するときは、WebGLContext に bind → set → unbind とする必要がある
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo);

      • バッファにデータをセット
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);

      • バッファのバインドを無効化
        gl.bindBuffer(gl.ARRAY_BUFFER, null);

    • Index Buffer Object(IBO)

      • バッファオブジェクトの生成
        var ibo = gl.createBuffer();
      • バッファをバインドする
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
      • バッファにデータをセット
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), gl.STATIC_DRAW);
      • バッファのバインドを無効化
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  • VBO と IBOを登録
    シェーダー内の各変数(attribute変数、uniform変数)
    attribute変数...頂点ごとに異なるデータ
    uniform変数...頂点ごとに同じデータ

    • gl.getAttribLocation() gl.enableVertexAttribArray() gl.vertexAttribPointer() を利用してVBOを登録
    • gl.getUniformLocation() gl.uniformMatrix4fv() を利用して IBOを登録
  • 描画
    これまでの処理はプログラム開始時に1度だけ行えば良い
    描画は毎フレーム行う

    • canvasを初期化
      gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clearDepth(1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    • インデックスを用いた描画命令
      gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);

    • コンテキストの再描画
      gl.flush();