doxasさんのサンプルコードを読んでみた


いきなりですが、これを投稿しているぽっぽこエンジニアは昨年、WebGL総本山やWebGLの開発支援サイトwgld.orgを運営している、杉本 雅広さんによるGLSLの講義を受けていました。
今さらながら、その中で配布されるJSのサンプルコードを、ぽっぽこエンジニアが頑張って読んでみました。

残念ながらコードは公開しないので、描画まではどんな流れなんだろう?なメモになっています。(読みにくくてすみません)

内容に入っていく前に
前置きとしてこの記事内では、gl は WebGLコンテキストを指します。

WebGL を実行するための初期化処理を行う。

  • canvas を取得する。

  • canvas から WebGL コンテキストを取得する。

    • const gl = canvas.getContext(contextType);
      • contextType: ここでは WebGL なのでwebglを指定。

シェーダやテクスチャ用の画像など読み込む処理を行う。

  • シェーダのソースコードを外部ファイルから取得する。

  • WebGLShader を作成。

    • gl.createShader(type);
      • type: gl.VERTEX_SHADERgl.FRAGMENT_SHADERのどちらか。
  • WebGLShader のソースコードを設定。

    • gl.shaderSource(shader, source);
      • shader: ソースコードを設定する WebGLShader オブジェクト。
      • source: 設定する GLSL ソースコードを含む DOMString 。
  • GLSL シェーダーをバイナリへコンパイル。

    • gl.compileShader(shader);
      • shader: フラグメントか頂点の WebGLShader 。
  • 正しくコンパイルされたかチェック。

    • gl.getShaderParameter(shader、pname);
      • shader: 情報を取得する WebGLShader 。
      • pname: ここではコンパイルが成功したかの確認なのでgl.COMPILE_STATUSを指定。
  • (失敗していたら)診断メッセージや警告メッセージなどの情報を返す。(ここではエラーログを吐くようにする)

    • gl.getShaderInfoLog(shader);
      • shader: 情報を取得する WebGLShader 。
  • WebGLProgramオブジェクトを作成、初期化する。

    • gl.createProgram();
  • フラグメントか頂点のどちらかの WebGLShader を WebGLProgram オブジェクトにアタッチする。

    • gl.attachShader(program, shader);
      • program: WebGLProgram オブジェクト。
      • shader: フラグメントか頂点の WebGLShader 。
  • WebGLProgram オブジェクトにアタッチされた頂点とフラグメントのシェーダーをリンクする。

    • gl.linkProgram(program);
      • program: リンクする WebGLProgram オブジェクト。
  • 正しくリンクされたかチェック。

    • gl.getProgramParameter(program, pname);
      • program: 情報を取得する WebGLProgram オブジェクト。
      • pname: ここではリンクが成功したかの確認なのでgl.LINK_STATUSを指定。
  • (成功していたら)WebGLProgram オブジェクトを現在の描画ステートの一部として設定する。

    • gl.useProgram(program);
      • program: 使用する WebGLProgram オブジェクト。
  • (失敗していたら)診断メッセージや警告メッセージなどの情報を返す。(ここではエラーログを吐くようにする)

    • gl.getProgramInfoLog(program);
      • program: 情報を取得する WebGLProgram オブジェクト。
  • attribute location をプログラムオブジェクトより取得する。

    • gl.getAttribLocation(program, name);
      • program: attribute 変数を含む WebGLProgram オブジェクト。
      • name: location を取得する attribute 変数の名前。
  • attribute 変数に対応するストライドを配列に入れておく。(あとで使うことになるので、先に変数に格納しておく)

    • ストライドとは、頂点属性あたりの要素数のこと。float なら1、vec2 なら2、vec3 なら3。
  • uniform location をプログラムオブジェクトより取得する。

    • gl.getUniformLocation(program, name);
      • program: uniform 変数を含む WebGLProgram オブジェクト。
      • name: location を取得する uniform 変数の名前。
  • uniform 変数に対応するタイプを配列に入れておく。(あとで使うことになるので、先に変数に格納しておく)

    • uniform2fv(vec2 の float の配列)やuniform4fv(vec4 の float の配列)など。

WebGL のレンダリングを開始する前のセットアップを行う。

  • 頂点座標を定義しておく。

    • 頂点は単純に配列として定義すればよい。GLSL 側で vec3 なら 3個 1セット、vec2なら 2個 1セット、float なら単体の値。
  • 定義した頂点の情報(頂点属性)は VBO(Vertex Buffer Object)に変換しておく。

    • VBO とは
      • 頂点座標のデータをまとめて書き込み送ることで、CPU と GPU の通信回数を抑えることができる。
    • 頂点や色といったデータを格納する WebGLBuffer を作成。
      • gl.createBuffer();
    • WebGLBuffer をターゲットにバインド。
      • gl.bindBuffer(target, buffer);
        • target: バインドするターゲットの GLenum。
          • gl.ARRAY_BUFFER: 頂点の属性を含むバッファーで、頂点座標、テクスチャ座標データや、頂点色データのようなもの。
          • gl.ELEMENT_ARRAY_BUFFER: 要素の位置指定に使われるバッファー。
        • buffer: バインドする WebGLBuffer 。
  • バッファーオブジェクトに頂点座標を転送。

    • gl.bufferData(target, size, usage);
      • target: バインドするターゲットを指定する GLenum。
      • size: GLsizeiptr のバッファーオブジェクトのデータストアのサイズ。
      • usage: データストアの用途を指定する GLenum 。(ここではgl.STATIC_DRAW
  • 背景をクリアする。

    • gl.clearColor(red, green, blue, alpha);
      • 各引数 0.0 〜 1.0 で指定。

WebGL を利用して描画を行う。

  • canvas のサイズを指定。

  • WebGL 上のビューポートも canvas の大きさに揃える。

    • gl.viewport(x, y, width, height);
  • あらかじめ指定されていたクリアカラーで canvas をクリアする。

    • gl.clear(mask);
      • mask: 消去されるバッファーを示す GLbitfield のビット論理和マスク。(ここではgl.COLOR_BUFFER_BIT
  • どのプログラムオブジェクトを使うのか明示する。

    • gl.useProgram(program);
      • program: 使用する WebGLProgram 。
  • VBO と attribute location を使って頂点を有効にする。

    • gl.bindBuffer(target, buffer);
      • target: バインドするターゲットの GLenum 。
        • gl.ARRAY_BUFFER: 頂点の属性を含むバッファーで、頂点座標、テクスチャ座標データや、頂点色データのようなもの。
        • gl.ELEMENT_ARRAY_BUFFER: 要素の位置指定に使われるバッファー。
      • buffer: バインドする WebGLBuffer 。
    • gl.enableVertexAttribArray();
      • 属性配列のリスト内の指定されたインデックスの一般的な頂点属性配列をオンにする。
    • gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
      • 現在バインドされているバッファーを現在の頂点バッファーオブジェクトの一般的な頂点属性にバインドし、そのレイアウトを指定する。
      • index: 頂点属性の場所を指定する GLuint。この場所が変更される。
      • size: 頂点属性あたりの要素数を指定する GLint。1, 2, 3 か 4 でなければならない。
      • type: 配列の各要素のデータ型を指定する GLenum。
        • gl.BYTE: 符号付き8ビット整数、値は-128、127
        • gl.SHORT: 符号付き16ビット整数、値は-32768、32767
        • gl.UNSIGNED_BYTE: 符号なし8ビット整数、値は0、255
        • gl.UNSIGNED_SHORT: 符号なし16ビット整数、値は0、65535
        • gl.FLOAT: 32ビットIEEE浮動小数点数。
      • normalized: 整数データを浮動小数点数へ型変換するとき、厳密な範囲へ正規化するかどうか指定する GLboolean 。
      • stride: 連続する頂点属性の始端どうしの間にある、オフセット数をバイト単位で指定する GLsizei 。
      • offset: 頂点属性配列の最初の要素のオフセットをバイト単位で指定する GLintptr 。
  • uniform location を使って uniform 変数にデータを転送する。

  • 転送済みの情報を使って、頂点を画面にレンダリングする。

    • gl.drawArrays(mode, first, count);
      • mode: 描画するプリミティブの種類を指定する GLenum 。
        • gl.POINTS: 単一の点を描画。
        • gl.LINE_STRIP: 次の線へと直線を描画。
        • gl.LINE_LOOP: 次の線へと直線を描画し、最後の頂点は最初のものに接続。
        • gl.LINES: 頂点2つごとに、その間に線を描画。
        • gl.TRIANGLE_STRIP
        • gl.TRIANGLE_FAN
        • gl.TRIANGLES: 頂点3つの集まりごとに、三角形を描画。
      • first: 頂点ベクトルの配列の開始インデックスを指定する GLint 。
      • count: 描画されるインデックスの数を指定する GLsizei 。
  • requestAnimationFrame();で繰り返し描画処理をする。

まとめ

後半に差し掛かるにつれ見慣れない単語とか増えてきたので、調べず一旦スルーすることにしました。
調べれば調べるほど沼だと思うので、可能な範囲で理解することを心がけます。(自分に甘い)

とりあえず主要人物はこんな感じかな、というのを画像にしてみたけれど…間違っていたらご指摘ください。

参考URL

MDN > WebGLRenderingContext