Edited at
WebGLDay 6

パラメトリック曲面を描くのに適した WebGL ライブラリについて

More than 1 year has passed since last update.


この記事は WebGL Advent Calendar 2015 の6日目の記事です。


パラメトリック曲面について

みなさん、パラメトリック曲面という言葉をご存じでしょうか?

2つのパラメータ(時間や角度などの媒介変数)によって決まる曲面のことを、パラメトリック曲面と呼ぶようです。

こんなのです。

graph.jpg

Parametrische Flächen und Körper

こんな図形が手軽に描けたらワクワクしてきませんか?

今回は「lightgl.js」という軽量 WebGL ライブラリを使いたいと思います。

まずは、三角形からです。


一番シンプルな例


index.html

<script src="lightgl.js"></script>



index.js

var gl = GL.create();

gl.ondraw = function() {
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.translate(0, 0, -2.5);
gl.color(0.0, 0.0, 1.0);
gl.begin(gl.LINE_STRIP);
gl.vertex( 0.0, 0.5, 0.0); // 頂点1
gl.vertex(-0.5,-0.5, 0.0); // 頂点2
gl.vertex( 0.5,-0.5, 0.0); // 頂点3
gl.end();
};


いかがでしょうか?エラーにならなければ三角形が描画されたかと思います。

基本的にパラメトリック曲面は gl.vertex() を用いて、3D 空間にプロットすることで実現します。

次にトーラスを描いてみましょう。


トーラスの例

lightgl_js_20150619_011.png

式は以下になります。

x = (R + r * cos(v)) * cos(u)

y = (R + r * cos(v)) * sin(u)
z = r * sin(v)

u は 0 ~ 2π
v は 0 ~ 2π


index.js

var angle = 0;

var gl = GL.create();

gl.onupdate = function(seconds) {
angle += 45 * seconds;
};

gl.ondraw = function() {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.loadIdentity();
gl.translate(0, 0, -2);
gl.rotate(60, 1, 0, 0);
gl.rotate(angle, 1, 1, 1);

// トーラス(Torus)の座標データを用意
// 1.0 y
// ^ -1.0
// | / z
// |/ x
// -1.0 -----------------> +1.0
// / |
// +1.0 / |
// -1.0
//
gl.begin(gl.POINTS);
gl.pointSize(2.0);
var ustep = Math.PI * 5 / 180;
var vstep = Math.PI * 5 / 180;
var R = 0.5;
var r = 0.2;
for (var v = 0; v <= 2 * Math.PI; v += vstep) {
for (var u = 0; u <= 2 * Math.PI; u += ustep) {
var x = (R + r * Math.cos(v)) * Math.cos(u);
var y = (R + r * Math.cos(v)) * Math.sin(u);
var z = r * Math.sin(v);
gl.color(x + 0.5, y + 0.5, z + 0.5, 1.0);
gl.vertex(x, y, z);
}
}
gl.end();
};

gl.fullscreen();
gl.animate();



lightgl.js の特徴

今回、lightgl.js を選んだのは以下の理由によります。


  • ライブラリが軽量(100KB以下)

  • 少ないコードで WebGL が使えるようになる。

  • 書き方が OpenGL に似ている(OpenGL を知っていれば移植が簡単)

  • 軽量ラッパである為、無駄が少ない(組み込み関数、組み込みシェーダ等は最低限のもしか用意されていない為、軽い)

ライブラリを使わないスクラッチの WebGL だと、先述のような簡単な三角形でも100行は軽く超えるので、ライブラリの恩恵が感じられるのではないでしょうか。


OpenGL / lightgl.js / processin.js との比較

OpenGL
lightgl.js
processing.js

float
var
var

int
var
var

sin()
Math.sin()
Math.sin()

cos()
Math.cos()
Math.cos()

glBegin()
gl.begin()
p.beginShape()

glEnd()
gl.end()
p.endShape()

glColor3d()
gl.color()
p.stroke()※

glPointSize()
gl.pointSize()
p.strokeWeight()

glVertex3d()
gl.vertex()
p.vertex()

GL_POINTS
gl.POINTS
p.POINTS

GL_LINES
gl.LINES
p.LINES

GL_LINE_STRIP
gl.LINE_STRIP
p.LINE_STRIP

※ processing.js の stroke 関数の色指定は 0~1 でなく 0~255 である為、注意。


パラメトリック曲面およびその他サンプル

ということで、色々と描画してみました。パラメトリック曲面でないものもありますが、ご了承ください。

タイトル
イメージ
lightgl.js
processing.js
Three.js
WebGL

三角形
三角形
Link
Link
Link
Link

リサージュ図形
リサージュ図形
Link
Link
Link
Link

3次元リサージュ図形
3次元リサージュ図形
Link
Link
Link
Link

ハーモノグラフ
ハーモノグラフ
Link
Link
Link
Link

3次元関数
3次元関数
Link
Link
Link
Link

波動方程式
波動方程式
Link
Link
Link
-

ローマ曲面
ローマ曲面
Link
Link
Link
-

貝殻曲面
貝殻曲面
Link
Link
Link
-

リンゴ曲面
リンゴ曲面
Link
Link
Link
-

スライム曲面
スライム曲面
Link
Link
Link
-

ハート曲面
ハート曲面
Link
Link
Link
-

トーラス
トーラス
Link
Link
Link
-

Wave Ball
Wave Ball
Link
Link
Link
-


追記(パフォーマンスについて)

コメント欄にて @emadurandal さんに教えて頂いたのですが、gl.vertex() は3次元空間にプロットするという意味合いでは分かりやすいのですが、パフォーマンスの観点からすると、かなり非効率なやり方のようです。

WebGL 的なテクニックとしては、VBO(頂点バッファオブジェクト)を使うことが推奨されているようです。

詳しくは、@emadurandal さんの9日目の記事「GPU本来の性能を引き出すWebGL頂点データ作成法 」を参照下さい。

また、lightgl.js でも VBO による描画モードが用意されています。サンプルについては、下記の「VBO 編」をご覧ください。


各種 WebGL ライブラリで基本図形を表示してみる

http://qiita.com/cx20/items/0fa19c96aa6470d98807