WebGL best practices
この文書は WebGL を使ったコンテンツの向上のための Tips について書きます。これらの提案に従うことで、多くの機器への互換性を高めたり、パフォーマンスを上げることにもなります。
避けたほうがいいこと
- WebGL のエラーを出さないように注意しましょう。エラーは
getError()
で得られますが、Firefox ではwebgl.verbose
の設定を有効にすることで、ウェブコンソールに WebGL のエラーと警告を出力します。ユーザーのコンソールにエラーを吐き出す必要はないでしょう?(訳註:パフォーマンスの理由もある。下参照) #ifdef GL_ES
は絶対に使ってはいけません。初期の例ではこれが使われていましたが、WebGL では必ず true になるので必要ありません。- フラグメントシェーダで
highp
精度を使うのはやめましょう。mediump
を代わりに使いましょう。highp
を使うと今のモバイルのハードウェアのほとんどで動きません。Firefox 11 からはgetShaderPrecisionFormat()
関数が実装されるので、highp
精度が使えるかどうかだけでなく、それぞれの精度の名称について実際の精度を知ることができます。
覚えておいたほうがいいこと
- WebGL の機能の中にはクライアントによって制限があるものがあります。そういうものを使う前には
getParameter()
を使って調べましょう。例えば、2D テクスチャのサイズはwebgl.getParameter(webgl.MAX_TEXTURE_SIZE)
でわかります。Firefox 10 からはwebgl.min_capability_mode
の設定があり、最低限の機能の環境をシミュレートすることができます。 - 特に、頂点シェーダでのテクスチャの使用は
webgl.getParameter(webgl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)
がゼロより大きくなければ使えません。現在のモバイルのハードウェアではまず使えないでしょう。 - WebGL の拡張が使えるかどうかはクライアントに依存します。できるならそれらの使用をオプションとし、サポートされていない環境にも対応できるようにしましょう。Firefox 10 からは
webgl.disable-extensions
の設定があり、拡張のない環境をシミュレートすることができます。 OES_texture_float
拡張がサポートされていたとしても、浮動小数点数テクスチャへのレンダリングはサポートされていないかもしれません。モバイルのハードウェアではまず動かないでしょう。サポートされているかを調べるにはcheckFramebufferStatus()
を使ってください。
一般的なパフォーマンスの tips
- CPU と GPU の同期を必要とするものはすべて、とても遅い可能性があり、メインのレンダリングループでは避けたほうがいいでしょう。
getError()
、readPixels()
、finish()
などの関数がそれです。getParameter()
やgetUniformLocation()
といった WebGL のゲッタも遅いので、JS 側で変数にキャッシュしてください。 - 大きい描画を少数だけしたほうがパフォーマンスが向上します(訳註:小さな描画をたくさん行うより)。1000 回の小さなものを描画するなら、一回の
drawArrays()
やdrawElements()
でやりましょう。一回のdrawArrays()
で離れたオブジェクトを描画するなら、3 点が一直線上にある三角形が使えます。 - 状態の変更が少ないほどパフォーマンスが向上します。特に、複数の画像をひとつのテクスチャにまとめて適切な座標を使うことでバインドしているテクスチャの変更が少なくて済みます。
- 小さなテクスチャは大きなテクスチャよりパフォーマンスが良いです。そのため mipmap が有効です。
- 簡単なシェーダーは複雑なものよりもパフォーマンスが良いです。特に、
if
文を減らせば速くなります。割り算やlog()
などの数学の演算もコストが高いです。