WebGLでお絵かき (2)

GLSLの型について

C言語に似ていますが、見慣れないものもあります。

GLSL C言語
void void
bool bool
int int
float float
vec2〜vec4 ベクトル(float[2]〜float[4])
mat2〜mat4 行列(float[2][2]〜float[4][4])

vec4は頂点の座標や色を表すのに使います。mat4は後述する座標変換で使います。

サイコロを描く

立方体を描くには正方形が6つ必要ですが、OpenGLでは三角形しか描けないので、12個の三角形を使います。

レンダリングした結果はこうなりました。

サイコロを動かしてみる

頂点シェーダの赤い部分を追加しました。前回追加したaPositionはattributeなので頂点ごとの値が入りますが、今回はuniformなので全ての頂点で同じ値になります。

attribute vec3 aPosition;
attribute vec3 aColor;
uniform mat4 uView;

varying lowp vec3 vColor;

void main(void) {
    gl_Position = uView * vec4(aPosition, 1.0);
    vColor = aColor;
}

GLSLでは、行列に対する乗算が定義されているので、乗算演算子が使えます。行列とベクトルの積は、どっちが行でどっちが列かややこしいですが、このような図を書くとわかりやすいと思います。

JavaScriptのコードを追加します。

scine.uniform = {
    view: gl.getUniformLocation(scine.program, "uView"),
};
const view = new Float32Array([
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1,
]);
gl.uniformMatrix4fv(scine.uniform.view, false, view);

uViewは変換行列で、この値によって拡大・縮小・回転・平行移動などの変換を行います。 uViewには単位行列を設定したので、(x, y, z)は同じ値になります。

実行した結果は当然同じです。

拡大・縮小

変換行列の対角成分を1以外に変更すると、拡大・縮小変換ができます。

const view = new Float32Array([
    1.5,   0, 0, 0,
      0, 0.5, 0, 0,
      0,   0, 1, 0,
      0,   0, 0, 1,
]);

実行結果はこのように、縦に潰れて横に伸ばされた形になります。

平行移動

4列目の成分を0以外に変更すると、平行移動できます。OpenGLに行列を渡すときは行優先なので、行と列が入れ替わっているように見えるので注意。

const view = new Float32Array([
      1,   0, 0, 0,
      0,   1, 0, 0,
      0,   0, 1, 0,
    0.4, 0.5, 0, 1,
]);

回転

3軸の回転の変換行列はややこしいですが、以下の数式を頑張ってJavaScriptのコードに置き換えます。