Open4

C-LegacyGL: シェーダー仕様の設計

okuokuokuoku

固定パイプライン用コマンドの復習

glShadeModelGL_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に纏められる。

okuokuokuoku

シェーダーのデザイン

TinyGLの仕様をGLES2で再現するにあたっては、事前に必要なぶんだけのシェーダーを生成しておく必要がある。

https://github.com/google/angle/blob/4b8573817f2a8e3358190aa01bc096318bc81eb0/src/libANGLE/GLES1Shaders.inc

ANGLEのGLES1実装はGLES3の機能性を使ってシェーダーを1つに纏めてしまっている。

頂点シェーダー

GL_TEXTURE_2D があるかどうかで、 GL_TEXTURE 行列をUniformとして持つかどうかが変わる。よって2バリエーション x ライトの処理数ぶんある。(法線のnormalizeはGLES2にも固定機能として残っているのでバリエーションにする必要はない)

  1. ライトの個数 (無効〜7個) ← GL_LIGHTING GL_LIGHTx
  2. テクスチャマッピングの有効/無効 ← GL_TEXTURE_2D
  3. マテリアルの追跡モード: (面 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になっているライトの数を数えて間を詰める処理が必要になる。

フラグメントシェーダー

超クッソ激烈に複雑。。 頂点属性のパースは頂点シェーダーでやんないとダメか。。以下の要素のかけ算になる:

  1. ライトの個数 (無効〜7個) ← GL_LIGHTING GL_LIGHTx
  2. テクスチャマッピングの有効/無効 ← GL_TEXTURE_2D
  3. テクスチャ環境 ← glTexEnvi -- TinyGLには GL_DECAL しか無いが GL_MODULATE は普通に欲しい

実際の処理自体はそこまで複雑ではないが、とにかくバリエーションが多い。。ANGLEのように条件分岐してしまえば簡単だが、特にモバイルではシェーダーの長さはパフォーマンスに直結するので可能な限りケチっていきたいところ。。

okuokuokuoku

TinyGLを拡張したいところ

普通にアプリを作るうえで表現上どうしても必要な最低限は追加したい:

  • glTexEnviGL_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 には有るので。。)