WebGL を利用して描画するまでの流れ
概要
WebGLを利用して描画する場合、描画までに実行する API のお約束が多い。
これは描画に必要なパラメータが膨大なため、 各API関数を呼び出して、グローバル変数である WebGL コンテクストの状態を変更していくことで、 描画に必要なパラメータを設定していく設計思想になっているためと思われる。
また WebGL の元となった OpenGL は GPUハードウェアの制約の中で パフォーマンス向上のために API を追加し続けてきたため、 同じ描画を行う上でも、様々な方法がある(現在では推奨されないAPIもたくさん存在する)
流れ
- GLContextの作成
var c = document.getElementById('canvas'); var gl = c.getContext('webgl');
シェーダーの生成
- 頂点シェーダ
- フラグメントシェーダ
- シェーダーの生成
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();