C-LegacyGL: シェーダー仕様の設計
とりあえず TinyGL のLIMITATIONS https://github.com/okuoku/tinygl-cmake/blob/master/TinyGL/LIMITATIONS から読み取れる仕様をシェーダーの仕様に起こしていく。
例えばFlat shadingのようにGLES2では表現できない機能は落した方が良いかな。
固定パイプライン用コマンドの復習
glShadeModel
は GL_FLAT
または GL_SMOOTH
を受ける。 GL_FLAT
に相当する機能はGLES2には無い。デフォルトは GL_SMOOTH
。
glMatrixMode は GL_MODELVIEW
GL_PROJECTION
GL_TEXTURE
の全てを受ける。これは普通にクライアント側で計算してUniform経由で渡してしまえば良いだろう。要するに頂点kick直前に全部設定する形にする。
glMaterialfv / glMaterialf / glColorMaterial / glLightfv / glLightf / glLightModeli / glLightModelfv は GL_LIGHTING
および GL_COLOR_MATERIAL
のパラメタを設定する。これらもUniformで渡すことになる。
glVertexPointer / glNormalPointer / glColorPointer / glTexureCoordPointer は、クライアント上のポインタを受ける。C-WebGLではBuffer経由のポインタしかサポートしていないがTinyGLでは逆にクライアント上のポインタしかサポートしていない。(あと、 glDrawArrays
に相当する機能はTinyGLに存在しない。index bufferも同様。) これらは全てAttributeに纏められる。
シェーダーのデザイン
TinyGLの仕様をGLES2で再現するにあたっては、事前に必要なぶんだけのシェーダーを生成しておく必要がある。
ANGLEのGLES1実装はGLES3の機能性を使ってシェーダーを1つに纏めてしまっている。
頂点シェーダー
GL_TEXTURE_2D
があるかどうかで、 GL_TEXTURE
行列をUniformとして持つかどうかが変わる。よって2バリエーション x ライトの処理数ぶんある。(法線のnormalizeはGLES2にも固定機能として残っているのでバリエーションにする必要はない)
- ライトの個数 (無効〜7個) ←
GL_LIGHTING
GL_LIGHTx
- テクスチャマッピングの有効/無効 ←
GL_TEXTURE_2D
- マテリアルの追跡モード: (面 front / back / front_and_back) x (
GL_EMMISION
/GL_AMBIENT
/GL_DIFFUSE
/GL_SPECULAR
/GL_AMBIENT_AND_DIFFUSE
) ←GL_COLOR_MATERIAL
(生成したvaryingを使わずに捨てるとGLES2実装が発狂することがあるので、基本的に無駄なvaryingは生成しないのが無難)
頂点シェーダーはライトで頂点カラーを変調して出力する。ライトは個別にOn/Offできてしまうので、描画時にOnになっているライトの数を数えて間を詰める処理が必要になる。
フラグメントシェーダー
超クッソ激烈に複雑。。 頂点属性のパースは頂点シェーダーでやんないとダメか。。以下の要素のかけ算になる:
- ライトの個数 (無効〜7個) ←
GL_LIGHTING
GL_LIGHTx
- テクスチャマッピングの有効/無効 ←
GL_TEXTURE_2D
- テクスチャ環境 ←
glTexEnvi
-- TinyGLにはGL_DECAL
しか無いがGL_MODULATE
は普通に欲しい
実際の処理自体はそこまで複雑ではないが、とにかくバリエーションが多い。。ANGLEのように条件分岐してしまえば簡単だが、特にモバイルではシェーダーの長さはパフォーマンスに直結するので可能な限りケチっていきたいところ。。
TinyGLを拡張したいところ
普通にアプリを作るうえで表現上どうしても必要な最低限は追加したい:
-
glTexEnvi
でGL_MODULATE
-- そもそもオリジナルのTinyGLだとライティングとテクスチャが同時に使えない(頂点カラーは生成してるのに) - Depthのdisable
- 複数インスタンス
前2つは https://github.com/C-Chads/tinygl でも実装されている。
Depthのdisableが無いとUIを書く前にdepthをクリアしないといけないという問題があるけど、そもそもUIはコンポジションAPIを別に用意してそっちで書いた方が効率的な気はするんだよな。。あとブレンディングが無いとUIで半透明が使えないというごもっともな問題もある。
諦める
普通に考えると以下も欲しいんだけど、今回は諦める。
- Scissorとステンシル。複数ビューポートのレンダリングは複数インスタンスを駆使してRender to textureすれば良いんじゃないかなということで。。コンポジション(2D描画)は別にAPIを持つ(TinyGLはテクスチャ最大サイズが256なので画面を合成できない)。
- ブレンディング。 ...超悩んだけど、まぁTinyGLは無し、GLESバックエンドでは有りって事で良いんじゃないだろうか。。PortableGLみたいな別のソフトウェアレンダラでは実装するみたいな割り切りで。
(機能的にはブレンディングは欲しい。。Glide https://github.com/sezero/glide には有るので。。)