WebGLフレームワークを作る Part1 なぜ作るのか
はじめに
WebGLに関して「コピべで慣れる生WebGL」という記事を1年近く前に書きました。
three.jsの次のステップとしてまずはWebGL APIを直接使ってWebGLをレンダリングしていくきっかけになればと思い、作成しました。
未だにちょくちょく読まれているようで、嬉しい限りです。
私が仕事でも個人制作でも使っているWebGLフレームワークについて説明したいと思います。
現在dan-shari-gl(断捨離GL)というフレームワークを作りながら、使っています。
APIのドキュメントはこちらです。
サンプルはこちらです。
断捨離GLはthree.jsのようなシェーダーやwebgl APIを知らなくてもかける高機能ライブラリではありません。Webgl APIを書きやすくするフレームワークです。
WebGL APIだと簡単な状態変化でも3,4行書かないといけない部分がありますが、関数化して、1行で済むことができるようにしています。頻繁に使う作法をなるべく簡略化出来ます。
基本コンセプトはパフォーマンスを最大限までチューニングする。
だからなるべく使えるところはWebGL APIのままにして、手をつけてません。必要に応じて関数やクラスを作成しています。
その分、three.js(558KB)やpixi.js(353KB)と違ってファイルサイズはminify版で27KBです。
日々、断捨離GLを使いながら個人制作・勉強・仕事に使っています。
以下はこれまでの制作や仕事の一部です。
個人制作
個人的にPBR(Physically based rendering)を勉強しています。(ロード時間が少しかかると思います。)
仕事
トップページのWebGLをお手伝いしました。
このトップページが「わたし、定時でで帰ります。」のPC画面に写ったそうです笑
私は2017年の中旬から自作のWebGLフレームワーク作ってますが、何個か作りながらも開発断念し、作り直し続けて今の断捨離GLになりました。
WebGL自作フレームワークを作るというテーマで主に3つに分けて書いていきたいなと思います。
part1 なぜ作るのか
part2 作ってみる
part3 使い続ける
なぜ自作フレームワークを作るのか?
大きく3つの理由があります。
1. パーフォーマンスと見た目を1%でも向上させたい。
2. ライブラリの中がブラックボックスだった。
3.同業者で作ってる人がいた。
1. パーフォーマンスと見た目を1%でも向上させたい。
2016年から2018年までオランダでWebGLデベロッパーというWebGL専門職についていました。
もっとパフォーマンス上がらないのか、デバイスごとに適した見た目とは何か。そういう問題に日々直面してました。
mozillaがWebGL best practicesを記しており、WebGL書く方なら一度は目を通すべき資料です。
理解に苦しんだものは以下の説明でした。
Fewer, larger draw operations will improve performance. If you have 1000 sprites to paint, try to do it as a single drawArrays() or drawElements() call.
訳) より少なく、より広く描画手続きをするとパフォーマンスは向上する。もし100体描画するものがあるとしたら、drawArrays()かdrawElements()を1回だけ実行するようにしましょう。
Fewer state changes will also improve performance.
訳) より少ないstateの変化はパフォーマンスを向上する。
なぜ理解に苦しんだのか。
メインで使用していたライブラリthree.jsはdrawArrays()とdrawElements()をどこでやっているのかを知らなくても、webglがレンダリングできるからです。
つまり、
2. ライブラリの中がブラックボックスだった。
自分はthree.jsのAPIは知っていても、WebGL知ってると言えない状況でした。(今は当時より知っていますが、知らないことが多すぎます。発見・勉強しながら、断捨離GLをアップデートしています。)
three.jsは行列・ベクトルなどの数学の知識やシェーダーなどの知識もなくても3Dをweb上で描画することが可能です。よりリッチに表現したいときにはシェーダーなど独自でカスタマイズできます。
three.jsのHello Worldのコードです。
var camera, scene, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;
scene = new THREE.Scene();
geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render( scene, camera );
}
上記のコードの以下のことを行っています。
- WebGLの描画を行うrendererを定義します。
- 描画の際に使用するステージ(scene)とそれを映すカメラ(camera)を定義します。
- 3Dの形であるgeomteryとその表面であるmaterialを定義し、それをベースに3Dオブジェクトmeshを定義します。
- 定義したmeshをsceneに配置します。
- 毎フレームsceneとcameraを使ってrendererを描画します。
見てわかるようにどこにもdrawArrays()とdrawElements()がでてきません。。
three.jsは現在のr104で50,000行近くもあり、webglのレンダリング部分でも10個以上のファイルとコアになるrenderers/WebGLRenderer.jsは2500行以上あります。
コアでthree.jsがどのように動いているかを知るにはシェーダーの知識だけじゃなくWebGL APIの何が呼ばれているのか知る必要があります。
CPUでどの行列計算を行い、GPUでどの行列計算を行うかということを理解しないといけません。
three.jsを使用してる優秀なwebgl developerのツイートなどを見ながら、自分で試しパフォーマンスと見た目の向上をなんとか必死にやってました。
彼らのやってる作法を真似して、多少のパフォーマンスは向上しても、それがなぜなのか理解できないと意味がなく、応用性が限定されていました。
3. 同業者で作ってる人がいる
makemepulseというパリ・ロンドン・LAに会社を持つデジタルメインの制作会社があります。技術ブログで自分たちが使用している独自のWebGLフレームワークについての説明の記事を読み、衝撃的でした。とても感動しました。
makemepulseの仕事はどれもクオリティーとパフォマンス全て高いです。
この記事ではどのような技術的なチャレンジを行い、自分たちのフレームワークを作ってそれをいかに実現しているかを丁寧に説明しています。十回以上は読みました。
彼がこの記事での冒頭でなぜNanoGLという独自のフレームワークを作ったかについて以下のように述べています。
- three.jsを使っていたが、three.jsは高度に発達していて、多くの部分がよくわからなかった。
- three.jsで色々とやろうとするとトリッキーなことをやってなんとか開発した。
- ちょっとしたことをやるのにファイルサイズの大きい高機能なライブラリをロードする必要があるのかという疑問(これは決してthree.jsをディスってるわけではないし、必要かどうかを議論しているのではない。)
- 複雑なことを作成するのに近道はない。ローレベルで何が行われているか知る必要がある。
LODやPBRなどテクニカルなことをどのように実装しているかも書いてあります。非常に興味深いです。
ぼくの心の中では、
やはりthree.jsではwebglのことを知るには限界がある。
時間かかると思うが、自分でWebGLフレームワークを作りながら使うことで、WebGL APIだけでなく、レンダリングで何がボトルネックになっているのかについて知ることができるんじゃないの。
じゃ、作ってみよう。
決心しました。
2017年11月、WebGLフレームワークの作成を開始しました。
次回はどういうところからフレームワークを作り、失敗し、新たに作り始めたかの開発過程について書きたいと思います。
この記事が気に入ったらサポートをしてみませんか?