OpenGL 系はほとんど使っていないので、余りよくわかっていないことが多いです。
とりあえずシェーダーのバリエーション管理をどうするか。
Direct3D11 では D3DCompile() 命令にプリプロセッサ用のデータを渡すことが
できます。シェーダーコンパイラは Direct3D11 より中立化しました。
D3DCompiler.h / d3dcompiler.lib と独立したモジュールになっており、
FeatureLevel や D3D のナンバーと関係なく共通で使用します。
include に対応するためには ID3DInclude を定義します。
define シンボルを渡す場合は、D3D_SHADER_MACRO 構造体の配列を作っておきます。
(Direct3D 10 Shader4.0 シェーダーのコンパイル)
Shader の機能わけのために、これまでプリプロセッサ命令を活用してきました。
同じシェーダープログラムでもシンボル定義に応じて複数の機能に対応させます。
D3D_SHADER_MACRO deflist[]= { { "SF_ANIMATION", "1", }, { NULL, NULL }, };
例えば上記の配列を D3DCompiler() に渡すと、hlsl 上では SF_ANIMATION の定義が
“1” になります。
シェーダー (hlsl) 上では
#if SF_ANIMATION ~ #endif
といった感じでコンパイル時の機能指定に応じてコードを分けることができます。
OpenGLES の GLSL コンパイラの場合、特にプリプロセッサ用の定義データを
そのまま渡すわけではなさそうです。
glShaderSource() では、一度のコンパイルでも複数のソースを同時に渡すことができます。
このうち 1つをプログラム内で生成したテキストに割り当てます。
例えばシェーダーコンパイル時に
#define SF_ANIMATION 1
といったテキストを生成してソースの 1つとして与えることで、D3D_SHADER_MACRO
と同じような使い方ができました。
OpenGLES2.0 はシェーダーのみと割り切ったおかげで無駄のないすっきりした
構成になっているようです。
シェーダーの世代的には ShaderModel3.0 相当と思われます。
Direct3D9 + ShaderModel3.0 の場合も、多くの機能がシェーダーで汎用化された
ために従来固定機能だったパイプラインの機能がいくつか使えなくなっています。
それでも API 的には重複する固定機能の設定が残っていたため、どちらでも動くのか
どうか、使えるのかどうかなどわかりにくい点がありました。
この問題は Direct3D10 でいったんリセットすることで解消しています。
Direct3D 10 以降はシェーダーのみと割り切って、重複する固定機能の多くを
排除しました。
そういう意味では OpenGLES2.0 は、Direct3D9 + ShaderModel3.0 というよりも、
Direct3D10 + ShaderModel4_0_Level_9_3 の方により近いといえるかもしれません。
関連エントリ
・Direct3D11/DirectX11 (4) FeatureLevel と旧 GPU の互換性、テクスチャ形式など
・Direct3D 10 Shader4.0 シェーダーのコンパイル