たくさんのアプローチがありますが、完璧なものはありません。
glAttachShader
シェーダーを組み合わせて使用することでコードを共有することは可能ですが、これにより構造体宣言や#define
-d定数などを共有することはできません。機能を共有するために機能します。
渡される文字列の配列をglShaderSource
コードの前に共通の定義を追加する方法として使用したい人もいますが、これにはいくつかの欠点があります。
- シェーダー内から何を含める必要があるかを制御するのは困難です(これには別のシステムが必要です)。
- これは、
#version
GLSL仕様の次のステートメントにより、シェーダー作成者がGLSLを指定できないことを意味します。
#versionのディレクティブは、コメントと空白を除いて、他の何かの前にシェーダで発生する必要があります。
この文のためglShaderSource
、#version
宣言の前にテキストを追加するために使用することはできません。これは、その#version
行をglShaderSource
引数に含める必要があることを意味します。つまり、GLSLコンパイラインターフェイスは、使用するGLSLのバージョンを何らかの方法で通知する必要があることを意味します。さらに、a #version
を指定しないと、GLSLコンパイラはデフォルトでGLSLバージョン1.10を使用します。シェーダー作成者#version
が標準的な方法でスクリプト内を指定できるようにする場合#include
は、#version
ステートメントの後に何らかの方法で-sを挿入する必要があります。これは、GLSLシェーダーを明示的に解析して#version
文字列(存在する場合)を検索し、その後にインクルードすることで実行できますが、#include
これらのインクルードを作成する必要がある場合は、より簡単に制御するためにディレクティブを使用することをお勧めします。一方、GLSL #version
は行の前のコメントを無視するため、ファイルの上部にあるコメント内のインクルードにメタデータを追加できます(うん)。
質問は次のとおりです:の標準的な解決策はあり#include
ますか、それとも独自のプリプロセッサ拡張を展開する必要がありますか?
GL_ARB_shading_language_include
拡張機能はありますが、いくつかの欠点があります。
- NVIDIAのみでサポートされています(http://delphigl.de/glcapsviewer/listreports2.php?listreportsbyextension=GL_ARB_shading_language_include)
- 事前にインクルード文字列を指定することで機能します。したがって、コンパイルする前に、文字列
"/buffers.glsl"
(で使用される#include "/buffers.glsl"
)がファイルの内容buffer.glsl
(以前にロードしたもの)に対応することを指定する必要があります。
- ポイント(2)でお気づきかもしれませんが
"/"
、Linuxスタイルの絶対パスのように、パスはで始まる必要があります。この表記法は一般にCプログラマには馴染みがないため、相対パスを指定できないことを意味します。
一般的な設計では独自の#include
メカニズムを実装しますが、#if
条件付きコンパイル(ヘッダーガードなど)を適切に処理するために、他のプリプロセッサ命令も解析(および評価)する必要があるため、これは難しい場合があります。
独自のを実装する場合、それを実装する#include
方法にもいくつかの自由があります。
- 事前に文字列を渡すことができます(など
GL_ARB_shading_language_include
)。
- インクルードコールバックを指定できます(これはDirectXのD3DCompilerライブラリによって行われます)。
- 通常のCアプリケーションで行われるように、常にファイルシステムから直接読み取るシステムを実装できます。
簡略化として、プリプロセスレイヤーの各インクルードにヘッダーガードを自動的に挿入できるため、プロセッサーレイヤーは次のようになります。
if (#include and not_included_yet) include_file();
(上記のテクニックを見せてくれたトレント・リードへのクレジット。)
結論として、自動、標準、および単純なソリューションは存在しません。将来のソリューションでは、いくつかのSPIR-V OpenGLインターフェイスを使用できます。その場合、GLSLからSPIR-VへのコンパイラはGL APIの外部にある可能性があります。コンパイラをOpenGLランタイムの外部に#include
配置すると、ファイルシステムとのインターフェイスに適した場所になるため、実装が大幅に簡素化されます。現在広く普及している方法は、Cプログラマーなら馴染みのある方法で動作するカスタムプリプロセッサを実装することだと思います。