🐮

WebGLがわからん

5 min read

WebGLを触る機会が年に1回ぐらいあるんですが、そのたびに苦労して頭を抱えたすえに、結局よくわからんという結論に至ります。理解がふわふわで固まらず、センスも足らず、なんだかなぁという気持ちでWebGLの難しさを整理しました。

WebGLに悩まされてる人がこれを見て、自分だけじゃないんだという一時の安心を得るための気休め記事です。シェーダー頑張りましょう。

修羅

WebGLの実装は、数学と美的感覚が必要とされる修羅の世界です。一方で、無味乾燥なWebの世界に潤いを与える素敵な技術でもあります。Zenlyのサイトを見てもらったら、通常のWebサイトにはない魅力を感じる人がいるかもしれません。

いざ、WebGLについて検索してみると、CodePenやGitHubなどに多くのサンプルが見つかります。こんなにたくさんサンプルがあるなら、なんとか実装できるかも〜と思ってしまうのが自然な考えですが、悲しいことにサンプルの多さと実装の易しさは比例しません。

そのサンプルを参考に、自分で考えて組んでみようと思うと、とたんに手が止まります。そこには概念への理解とセンスが必要になるからです。

WebGLの難しさ

WebGLの難しさには3つの側面があると思っています。

1つ目が数学。

いま見ているブラウザはきっと2Dなので、3Dのものを2Dに落とし込むために数学が必要になります。それが行列というやつです。行列は3D→2Dへの変換だけでなく、移動や回転などにも使われます。サイン・コサインなんて何の役に立つの?という定番のあるあるがありますが、少なくとも物体を回転させるために役立ちます。

Three.jsなどのライブラリではこの辺の大変な部分をラップしてくれていますが、カメラのアングルを良い感じにアニメーションさせたいとか、DOM上のテキストとWebGL上のモデルの位置を同期させたいとか考え始めると、ライブラリを使っていてもそれなりの計算が必要になります。

2つ目がシェーダー。

シェーダーというのは、一言でいうと3Dを描画するためのプログラムです。このシェーダーを通してGPUで処理ができるため、高いパフォーマンスが出せるわけです。WebGLでは、OpenGLと同様にGLSLというC言語に近い言語で記述します。シェーダーについてわかりやすく説明できる自信がないので、興味があったら wgld.orgThe Book of Shaders あたりを見てみてください。WebGLがわからんというよりも、OpenGLの独特の考え方が頭に入らん、の方が感覚的には近いかもしれない。

また、3Dではカメラやライティングなどの概念の理解が必要になります。これらはWebのフロントエンドでは馴染みがないですが、UnityやUnreal Engineのようなゲームエンジンではお馴染みの概念です。

OpenGLは、ゲームをはじめとした2D/3Dグラフィクスのための技術なので、Webエンジニアよりもゲームエンジニアのほうが、WebGLの理解は容易かもしれません。そもそも、WebGLがJSの延長にあると思ったら面食らうので、完全に別世界だと思ったほうが頭を切り替えられそう。

3つ目がセンス。

シェーダーの行き着く先は、ほとんどアートに近いと思います。GLSLの文法がわかることと、クールなシェーダーが書けることは同義ではありません。クールなものをクールだと思える感覚と、それをイメージどおりに実装できる腕力が必要になります。これが一番難しいです。

高度に最適化されたシェーダーは魔法と見分けがつきません。こんなものを理解して書ける人がいるのかと疑ってしまうレベルです。逆に言えば、センスのあるシェーダーを自在に書けるようになれば楽しい世界なんだろうな、とも思います。

センスとは関係ないですが、WebGLを触るようになってから、動画を見ていてめっちゃパーティクル飛んでるなぁ〜とか思うようになりました。

YoutTube - めっちゃパーティクルが飛んでるMV

ざっくり3D

WebGLを最初に学んだときを振り返って、3DモデルをWebに持っていくためのざっくりした部分だけでも先に知っておきたかったなと思ったので、そこらへんをまとめました。

まずはポリゴンから。

ポリゴンの単語の意味は多角形ですが、3Dの文脈では三角形か四角形を指すことが多いです。四角形はふたつの三角形で表現できるので、とりあえず三角形ということにしておきましょう。一見複雑に見える3Dモデルも、大量のポリゴンによって構成されています。

なぜこんな面倒なことをするかというと、その方がコンピューターに優しいからだと理解しています。コンピューターで複雑な曲面を描画しようとすると複雑な計算が必要になりますが、ポリゴンの集合として表現すれば、最終的には頂点の集合として扱えるため、コンピューターで処理がしやすいです。Illustratorやイージングなどで使われているベジェ曲線というやつがありますが、これもコンピューターに優しい仕様になっていて、複数の座標をもとに曲線を描画します。

ポリゴンの数は多ければ多いほど精密なモデルになりますが、そのぶん容量も大きくなります。何も考えずにモデルを出力すると10MBぐらいあったりします。恐ろしいですね。ローポリと呼ばれるポリゴン数の少ない3Dモデルであれば、容量を抑えながら愛嬌のある表現ができるので、必ずしもポリゴン数が多いほど良いという訳ではありません。ちなみに、上に貼ってるローポリのポリゴン数は292個です。このぐらいであれば数10KB程度に抑えられるので健全です。

ポリゴンを集めてできるのはあくまで3Dモデルの形状なので、その表面にテクスチャを貼り付けます。テクスチャというのは3Dモデルに貼り付ける画像だと思っておけばだいたい合ってると思います。3Dに貼るテクスチャを2Dで表現しているので、こんな感じの変な画像になります。

glTF is the "JPEG of 3D"
https://www.khronos.org/api/index_2017/gltf

これでそれっぽい3Dモデルができたので、データを書き出していきます。Web向けの書き出しには、3DのJPEGこと、glTFを使うとスムーズです。出力されるファイルはJSONなので親近感が湧きます。ただ、glTFの場合はテクスチャなどが別ファイルで書き出されるため、より最適化されたglbというバイナリの方が本番には適していると思います。( .gltf の方が人間に優しく、 .glb の方がコンピューターに優しいイメージです)

Webで使うにはまだ重いと思うので、Dracoというライブラリで圧縮した方が良いかもしれません。場合によっては 1/10 程度まで落とせます。圧縮した場合、読み込み側でデコードする必要があるので注意してください。Three.jsであれば DRACOLoader を使えば大丈夫です。容量は圧縮できますが、そのぶんデコードに時間がかかるので、そこはトレードオフになります。

こうして3Dモデルが出力できたわけですが、まだリアリティが足りません。現実の世界には光があり、陰影があります。そこで、3Dの世界にライトを設置します。

最後に、3Dをブラウザに描画するためにカメラを使います。カメラで写真を撮るということは、4次元の現実を2次元の静止画に切り取る行為なので、それをWebGLでもやるわけです。

最終的な出力は canvas に描画される2次元の静止画になります。

ただの静止画では魅力が半減してしまうので、動きをつけて requestAnimationFrame で更新することで、いわゆるWebGLのサイトが出来上がります。

以上です。牛かわいい。


https://www.cs.cmu.edu/~kmcrane/Projects/ModelRepository/

ありがたいサイト

おまけ

なんか3Dって楽しそうと思える動画を置いておきますね。(Unityですが)

YouTube - あなたもUnity、はじめてみませんか?

Discussion

ログインするとコメントできます