Subterranean Flower

WebGL用のJavaScript行列計算ライブラリMatrixGLを公開しました

Author
古都こと
ふよんとえんよぷよぐやま!!!

WebGLを扱う際には行列計算というのがどうしても必要になってきます。だいたいは既存のライブラリを使ってなんとかしたりするのですが、現状あまり選択肢は多くありません。そこで新しいライブラリであるMatrixGLを作って公開しました。

経緯

私はたまにWebGLをいじるのですが、やっぱりどうしても行列計算が面倒です。WebGL用の行列計算ライブラリというと、glMatrixという有名なライブラリがあるのですが、昔ながらのC言語的なAPIで、どうしてもJavaScriptでは使いにくく感じていました。OpenGL自体とは相性いいAPIだとは思うんですけどね。

「まあ誰かがそのうちJavaScript的な使いやすいの作ってくれるだろう」とずーーーーっと待っていたのですが、待てど暮らせど全く出てこないという状況でした。みんなglMatrixで満足してるのか、それかThree.jsとか使ってるから特に気にしてないのか。

探せば行列計算のライブラリは大量に出てくるのですが、どちらかというと数学向けのライブラリが多く、WebGL向けである数学のサブセットな感じのライブラリはあんまり見つかりませんでした。

もう数年待った気がするのですが、本当に全く新しいのが出てこないので、いっそ自分で作ることにしました。就職したのであんまりプライベートでプログラミングする時間はなくなったのですが、貴重な土日でバーっと仕上げてみました。

MatrixGL

私による行列計算ライブラリ、その名もMatrixGL!JavaScriptっぽいAPIと、WebGL向けの作りをしている行列計算ライブラリです。npmかgithubからダウンロードできます。

まだ出来立てのほやほやなので機能は少なく、最低限の計算しかできませんが、これから増やしていく予定です。まだクォータニオンとかないです。

(2018/02/07 追記)クォータニオンをサポートしました。

ライセンスはMITライセンスなので比較的自由に使えるはずです。好きにいじったり好きに再配布したり、お好きにどうぞ。

使い方

インストール(Node.jsなし/ブラウザ用)

インストールは簡単!githubからzipファイルをダウンロード(https://github.com/kotofurumiya/matrixgl/releases)してきて、中のbuildフォルダに入ってるmatrixgl.min.jsを取り出すだけ!他のファイルは捨ててしまえ。

あとは適当なHTMLファイルと同じフォルダにmatrixgl.min.jsを入れ、scriptタグで挿入します。

<script src="matrixgl.min.js"></script>
<script>
    // ここにコードを書いていく
</script>

これで準備OKです。

インストール(Node.js/npm)

MatrixGLはnpmでもインストールできます。

$ npm install matrixgl --save

あとはrequireなりimpotなりしてください。

const { Vector3, Vector4, Matrix4 } = require('matrixgl');

基本的な使い方

以下のような感じで使えます:

// 4次元ベクトルを作る
const vec = new Vector4(1, 2, 3, 4);

// 値を表示する(セットもできるよ!)
console.log(vec.x); // 1
console.log(vec.y); // 2
console.log(vec.z); // 3
console.log(vec.w); // 4

// 全部の値を表示する
console.log(vec.values);

普通にnewして普通にアクセスするだけです。Vector2、Vector3、Vector4があります。それぞれFloat32vector2、Float32Vector3、Float32Vector4のエイリアスです。

また、ベクトルの計算もできます。

const vec1 = new Vector4(1, 2, 3, 4);
const vec2 = new Vector4(5, 6, 7, 8);
const scalar = 5;

// 計算!
const vecSum = vec1.add(vec2);
const vecSub = vec1.sub(vec2);
const vecProd = vec1.mulByScalar(scalar);
const vecMag = vec1.magnitude;

よくあるOpenGL用の行列ライブラリと違って、メソッドを呼び出してもベクトルそのものは書き換えず、新しいベクトルを返すようになっています。これは行列でも同じです。

行列はMatrix2、Matrix3、Matrix4があります。それぞれMatrix2x2、Matrix3x3、Matrix4x4のエイリアスです。非正方行列はいまのところありません。

特にMatrix4はWebGLっぽい機能を備えています。モデル行列なんかをサクッと作れます。

const transform = Matrix4.identity()
                         .translate(1, 2, 3)
                         .rotateX(Math.PI)
                         .scale(5, 5, 5);

手動で組むこともできます。

const identity = Matrix4.identity();
const scaling = Matrix4.scaling(5, 5, 5);
const rotation = Matrix4.rotationX(Math.PI);
const translation = Matrix4.translation(1, 2, 3);

const transform = identity.mulByMatrix4(translation)
                          .mulByMatrix4(rotation)
                          .mulByMatrix4(scaling);

よくある”look at”ビュー行列なんかも作れます。

const camera = new Vector3(1, 2, 3);
const lookAt = new Vector3(4, 5, 6);
const cameraUpDirection = new Vector3(7, 8, 9);

const view = Matrix4.lookAt(camera, lookAt, cameraUpDirection);

プロジェクション行列も平行投影(orthographic)と透視投影(perspective)に対応しています。

const orthographic = Matrix4.orthographic({
  top: 1,
  bottom: -1,
  left: -1,
  right: 1,
  near: 1,
  far: 2
});

const perspective = Matrix4.perspective({
  fovYRadian: 60 * Math.PI / 180,
  aspectRatio: 1,
  near: 1,
  far: 2
});

このあたりは引数多いのでオブジェクトで渡すようにしました。もう引数の順番覚える必要ないです。

これでModelViewProjection行列が作れますね。

const mvp = perspective.mulByMatrix4(view)
                       .mulByMatrix4(transform);

と、こんな感じで使っていけます。

(2018/02/07 追記)クォータニオン

2018/02/07にリリースしたv0.1.0でクォータニオンをサポートしました。これにより任意軸についての回転が表現できます。

// クォータニオンを作成する
const q = new Quaternion(1, 2, 3, 4);

実際は直接クォータニオンを作成することはあまりなく、回転軸と角度を与えて生成するのが普通だと思います。以下のようにします:

// 回転軸を作る(Vector3)。軸は正規化されている必要がある
const axis = new Vector3(1, 2, 3).normalize();
const radian = 45 * Math.PI / 180;

// 軸axisについてradian度の回転を表すクォータニオンを作る
const q = Quaternion.rotationAround(axis, radian);

// クォータニオンを4x4の回転行列に変換する
const rotation = q.toRotationMatrix4();

球面線形補間(通称slerp)もサポートしています。

// 補間するには両方のクォータニオンが正規化されている必要があります
const q1 = new Quaternion(1, 2, 3, 4).normalize();
const q2 = new Quaternion(5, 6, 7, 8).normalize();

// 2つのクォータニオンの中間(t=0.5)を補間して作ります
const interpolated = q1.slerp(q2, 0.5);

WebGLと一緒に使う

もちろんMatrixGLはWebGLと一緒に使うことを前提としています。VectorもMatrixもQuaternionも、それぞれvaluesプロパティで中の値を取り出すことができ、これをWebGLに直接渡すことができます。

// Buffer
gl.bufferData(gl.ARRAY_BUFFER, vec1.values, gl.STATIC_DRAW);

// Uniform Variable
gl.uniformMatrix4fv(mvpLocation, false, mvp.values);

あとは普通に描画するだけです。

APIドキュメント

APIのドキュメントは https://kotofurumiya.github.io/matrixgl/ にあります。気になる人は見ておいてください。といってもまだここで紹介したメソッドぐらいしかないんですけどね。

今後の展望

とりあえず最小限のリリースはできたので、今後は機能を拡充していく予定です。特にクォータニオンは欲しいなーと思っているのでなんとかしたいです。

(2018/02/07 追記)クォータニオンをサポートしました。

機能の拡充といってもあんまりむやみに増やすことはしないと思います。あくまで数学用じゃなくてWebGL用なので、GLSLでサクッとできるようなことはMatrixGL側で実装しない可能性もあります。

何か要望があればgithubでissue(https://github.com/kotofurumiya/matrixgl/issues)を立てておくか、Twitterで言ってくれればなんらかの対応はします。issueは日本語でもいいですよ。