WebGLを試してみる

  • by haga
  • 2010/08/02 15:28
  • on
  •  

 初めまして、こん(にち|ばん|なはずで)は。ハガと申します。DeNAでは主に3D周りの開発とメンテナンスを担当しております。DeNAのサービスですと、あまり「3D」が強調されることは無いかもしれませんが、実は「モーションアバタ」や「セトルリン」は3Dのデータを使用したサービスなんです。

 3Dの描画を担当するサーバは、リクエストに応じて3Dのアバタ形状データを元に携帯のディスプレイに表示する絵をその場で作り上げて、GIFに変換して送り出しています。3Dのデータは2Dのデータと比べると量が多くて処理も大変なんですが、一度データを用意すれば自由な方向から見ることができたり、色々な変形を加えたりすることができるという利点もあります。「モーションアバタ」ではその特徴を活かして、好きなアバタに好きなモーションを組み合わせることができるようになっています。サーバの処理は重くて大変なんですが、そこは3D描画専用のサーバをたくさん用意してカバーしています。

 で、せっかく社内に3Dのデータが沢山あるんだし携帯以外のプラットフォームでも絵を出せないかなということで、最近WebGLでのレンダリングをやってみたので、そのお話でもしてみようかと思います。

WebGLってなに

 WebGLというのは、細かい話は放っておいて超大雑把に言うと、ウェブブラウザで3Dの絵を出せるようにする規格です。今までも、Flash他のプラグインをインストールすることで一部のサイトでは3Dのコンテンツを見ることができました。けど、プラグインとか無しでも3Dコンテンツを楽しめるように標準化していきましょうよ、というのがWebGLです。HTML5を御存知の方なら、Canvas要素で3Dの描画ができるようになりますよ、と言えば分かりやすいでしょうか?

 そのWebGLですが、次のような特徴があります。
  ・図形のデータは保持されないので、手続き的に絵を描く
  ・描けるものは基本的に三角形だけ
  ・絵を描く手続きには、JavaScriptを使う
  ・APIは、OpenGL ES 2.0をJavaScript向けにアレンジしたもの
  ・まだ使えない

 以下、一つずつ解説していきたいと思います。

図形のデータは保持されないので、手続き的に絵を描く

 DOMみたいな、図形や見た目を保持するデータ構造のような仕組みはWebGLにはありません。どのように絵を描くかを、自分でプログラムしないといけません。もともとCanvas要素がそんな感じみたいですから(すみませんCanvas要素をWebGL以外で利用したことが無いので、実はよく知りません・・・)その点では従来のCanvasと利用法が似てるといえば似てるかと思います(APIは全然違いますけど)。複雑なシーンの構造を保持する必要がある場合は、そのためのデータ構造とそれを扱うプログラムを、自分で作らないといけません。
 このような、手続きで絵を描いていく方式は、初心者にとっては利用するためのハードルがちょっと高いかもしれません。でもその分柔軟で、用意されたデータ構造に縛られない、自由な絵を描けるという利点があります。ハードルが高いという問題は、親切な誰かさんがきっと作ってくれるであろうライブラリを利用することで緩和することもできます。

描けるものは基本的に三角形だけ

 Canvas(2D)には円や2次3次のベジエ曲線を描画する機能があるみたいですが、WebGLは三角形だけです(他に一応、点と直線も描けます)。描けるのは三角形だけなんですが、その三角形に色々なバリエーションを作ることができます。色を付けたり、テクスチャを付けたり、陰影を付けたり。まぁそうは言っても結局は三角形なのですが。
 曲線や曲面は描画できないので、円とか球とかを描画したい場合は、カクカクに見えない程度まで細かく三角形に分割してやる必要があります。不便といえば不便なんですが、3Dグラフィックスハードウェアの都合でそうなってますので我慢してください。皆さんがお持ちの全てのゲーム機にも同じ制限があります。でもどのゲームも綺麗なグラフィックスを出せてるわけで、要は工夫と努力でなんとかなるってことです。

絵を描く手続きには、JavaScriptを使う

 Web系な皆さんには、JavaScriptでのプログラミングはお馴染みですね。多分。リアルタイム3Dグラフィックス系の方からWebGLに入ってくる人には、JavaScriptって遅いんじゃないの大丈夫なの?と思われるかもしれません。

 正直なところ、全然大丈夫じゃないくらい激遅いですJavaScript。覚悟が必要なレベル。

 ただWebGL自体は特に遅いわけではないので、JavaScriptはGLコマンドを発行するだけ、みたいに使えば大丈夫です。GPUでできる部分はなるべくGPUにまかせてCPUにはできるだけ仕事をさせない、という基本は、普通にC言語などからOpenGLを使う場合と同じです。その傾向がちょっと極端になった感じだと思えば良いと思います。
 とはいえ、OpenGLにはベクトルや行列の計算をおこなうようなAPIが無いので、その辺はJavaScriptで実装してやる必要があります。ベクトルや行列を大量に使うようなプログラムは、結構キツいです。

APIは、OpenGL ES 2.0をJavaScript向けにアレンジしたもの

 OpenGLというのは3Dの絵を描くためのAPIの一つなのですが、WebGLはそのなかの、OpenGL ES 2.0というバージョンを元に作られています。OpenGLは歴史が長いこともあって沢山のバージョンがあります。OpenGLを御存知でない方のためにスーパー適当な説明をしますと、以下のような感じになります。

 OpenGL 1.0 - 基本的な描画機能だけの元祖OpenGL
 ↓
 OpenGL 1.1~1.5 - OpenGL1.0にどんどん機能を追加していった
 ↓ → 派生
 ↓   OpenGL ES 1.0 - OpenGL 1.3 から要らない機能をバッサリ切り落とした
 ↓   ↓
 ↓   OpenGL ES 1.1 - 切り落とし過ぎちゃったので機能を追加した
 ↓
 OpenGL 2.0 - OpenGL1.xに「プログラマブルシェーダ」を追加したもの
 ↓ → 派生
 ↓   OpenGL ES 2.0 - OpenGL 2.0 から要らない機能をバッサリ切り落とした  ←WebGLこれ!
 ↓
 OpenGL 3.x, 4.x, ...

 WebGL仕様の元になっているのはOpenGL ES 2.0です。ESというのは for Embedded Systems の略で、メモリや演算能力の足りない組み込み用途向けに、必要最小限に絞った仕様になっています。詳細については、以下のリンクを参考にしてください。

 OpenGL ES → http://www.khronos.org/opengles/

 WebGL → http://www.khronos.org/webgl/

 

 OpenGLを御存知の方にOpenGL 2.0 ESを簡単に説明すると、

   式①― OpenGL ES 2.0 = OpenGL 2.0 - 不必要な機能
   式②― OpenGL 2.0 = OpenGL 1.x + プログラマブルシェーダ + VBO他各種オブジェクト
   式③― 不必要な機能 = OpenGL 1.x
   式①②③より、   OpenGL ES 2.0 = プログラマブルシェーダ + VBO他各種オブジェクト

 といった感じになります。OpenGL 1.xが残ってませんが、はい、残ってません。残念ですが固定パイプラインに関する機能はあらかた切り落とされてます。強制的にプログラマブルシェーダ&各種オブジェクトです。シェーダから組み込みのアトリビュートやステートを参照することもできないです。glTranslatef他、行列系のコマンドすらありません。自前でやることが増えて、けっこう面倒臭いです。

まだ使えない

 ここまで書いておいて今更ですが、まだ(正式には)WebGLを使えるブラウザがありません。ので、普通の人はWebGLのコンテンツがあっても表示できません。なんだそれ!

 ・・・ですが今年中のリリースができるよう、Webkitのnightly buildやMinefieldでのWebGL実装の開発は進んでいます。WebGLを試してみたい人はそれらのブラウザをダウンロード(&ビルド)する必要があります。当然、正式版ではないのでセキュリティの問題なんかもあるかもしれません。それでも人柱erの精神で試してみたい人は、以下の手順でMinefieldを導入してみるのが良いと思います。ビルド済みの実行ファイルがあるので簡単です。

  1.Minefieldをダウンロード  → http://nightly.mozilla.org/
  2.WebGLを有効化する
    1)Minefieldを立ち上げる
    2)アドレスバーに about:config と入力する
    3)"webgl.enabledforall_sites"の項目をtrueにする
  3.WebGLコンテンツを見てみる
    → ここのリンク集とか http://learningwebgl.com/blog/?p=1949
    → あるいは 「webgl sample」でぐぐるとか

(8/4追記)
  Macでは、この記事の下の方にあるデモをMinefieldで実行するとOSごと落ちてしまう場合があるようです。以下のWebKitの方を使用することをお勧めします。
  1.WebKitをダウンロード → http://nightly.webkit.org/
  2.ターミナルで次のコマンドを実行(WebGLを有効化する)
    defaults write com.apple.Safari WebKitWebGLEnabled -bool YES
  3.WebKitを起動する

 あと大切なことですが、WebGLは、ブラウザだけでは動きません。グラフィックスハードウェアが、「プログラマブルシェーダ」という機能を持っている必要があります。nVIDIAやATi(AMD)の最近のグラフィックスカードを装備しているPCなら大抵は動きますが、Intelだとかのチップセット組み込みグラフィックスだと動かない可能性が高いです。

使ってみると

 まだ結構、不安定だったり、明らかなバグもあったりしますね。今のところMinefieldでしか試していないんですが、長時間WebGLを動かした後にページをリロードすると、WebGLのコンテキストが作成できなくなったりします。ブラウザを再起動すれば直りますが。(と思ってたのですが最近のバージョンでは安定度増してるっぽい?) あと、Minefieldでは、glDepthMaskをいじるとおかしくなるみたいです。単に効果が出ないだけなら大きな問題も無い(?)のですが、後になって表示が崩れたりといった、よく分からない影響が出たりします。(と思ってたのですがこれもいつのまにか直ってた?) 他にも、ある時期からgetUniformLocation()の返り値がintから変更されてたり、Intel系のGPUではフラグメントシェーダ内でgl_FrontFacingが使えなかったり。Intelの方は、WebGL関係無いかもしれませんけど。

作ってみた

 で、まぁ色々と地雷を踏みつつも、WebGLでモーションアバタのデータをレンダリングするところまではできたので、それをテキトーにDeNAのトップページと重ねてみました。↓がそのサンプルです。

 http://engineer.dena.jp/webgl/sample01/avatar.html
 注意!
 ●上のリンクを見るには、WebGLが動くブラウザが必要です。(WebGLが動かない環境の方はごめんなさい。)
 ●場合によっては、OSごと固まる可能性もあります。作業中のファイルは保存して、覚悟を決めてから見てください。

 左上の方で動いているアバタの周囲512ピクセルが、マウスで操作できる範囲になっています。以下、簡単な操作説明です。

   マウスドラッグ: 回転
   Shift+ドラッグ: 移動
   Ctrl+ドラッグ: 奥行き方向の移動
   Shift+Ctrl+ドラッグ: 光源の方向を変える
   a: アニメーションon/off
   s: 影のon/off
   d/D: 陰を濃く/薄く
   f/F: 影を濃く/薄く
   g/G: 影を柔らかく/くっきりさせる
(8/4追記)
   Macでは、Ctrl+クリックで右クリック相当になってしまうことを忘れていました。Ctrlを使わなくて済むよう、以下の操作を追加しました。
   z + ドラッグ: 奥行き方向の移動
   x + ドラッグ: 光源の方向を変える

  こういうデモを作るとすぐ下から覗きこもうとする人がいますけど、ダメですよそういうことしちゃ。えっちなのはいけないと思います!

 ちなみにこのデモで使われている3Dデータは、モバゲータウンの「モーションアバタ」サービスで使われているものと全く同一のものです。モバゲータウンの方でこれを表示すると、下のような絵になります。

avatar.gif

これから

 WebGLが一般化すると、こんな感じで、Webページの上で動きまわる3Dの絵が見られるようになるかもしれません。JavaScriptが流行り始めた頃みたいに、WebGL使い過ぎで超見辛いページが一時的には氾濫しそうな気もしますが、多分そのうちJavaScriptと同じように落ち着いていくのではないかと思います。節度を持ってうまく使えば超coolなページを作れる(かもしれない)WebGLに、皆さんも注目してみませんか。