シェーダーのユニフォームを更新する最良の方法は何ですか?


10

シェーダーのマトリックスを最新の状態に保つための最も一般的な方法は何ですか?なぜですか?

たとえば、現時点ではShader、GLSLシェーダープログラムとユニフォームのハンドルを格納するクラスがあります。カメラを動かすたびに、新しいビューマトリックスをシェーダーに渡す必要があります。次に、すべての異なるワールドオブジェクトのモデルマトリックスをシェーダーに渡す必要があります。

そのシェーダーオブジェクトにアクセスしないと何もできないので、これは私を厳しく制限します。

ShaderManagerすべてのアクティブなシェーダーを保持する責任があるシングルトンクラスを作成することを考えました。その後、どこからでもアクセスできます。ワールドオブジェクトはShaderManager、目的のマトリックスを通知する必要があるだけで、どのシェーダーがアクティブであるかを知る必要はありませんが、これが最善の方法であるとは限らず、おそらくいくつかの問題があります。このアプローチを取ることから発生します。


レンダリングするときに、データをシェーダーに渡してみませんか?
Nick Caplinger 2013年

それが私の意図ですが、どうやって?1つのオブジェクトがシェーダーを作成する場合、ワールドオブジェクトは、そのシェーダーの存在について知り、それに必要な行列を渡すことをどのように意味しますか?
Lerp

回答:


11

使用均一バッファ(すなわち一定のバッファ D3Dの用語では)。

すべてのシェーダーがそのような各バッファーのレイアウトとバインディングポイントに同意している限り、更新は簡単です。モデルは、シェーダーについて何も知る必要はありません。それらは定数バッファー内のモデルビューマトリックスを更新するだけでよく、レンダリングパイプラインはそれを自動的に使用します。

少なくとも、そのようなバッファが2つあるべきだと主張します。1つ目は、射影行列、カメラ行列、連結されたカメラ射影行列、ビューポート情報、錐台の詳細、逆行列を格納する必要があります。このバッファを更新する必要があるのは、シーンごとに1回だけです。

次に、各モデルに別のバッファーを与えて、モデルビューマトリックス、法線マトリックス、逆行列、および材料特性を保存します。これはモデルごとに1回更新され、別の更新パスで実行できます(該当する場合/該当する場合)。複数のオブジェクト間でマテリアルを共有する機能がある場合は、マテリアル情報を3番目のマテリアル固有のバッファに移動できます。

フォワードシェーディングセットアップでは、すべてのライトを別のバッファーに配置することには意味があり、ディファードシェーディングでは、同様にライトパスにライトごとのバッファーを使用することも意味があります(モデルで使用されるモデル/マテリアルバッファーの代わりに)ジオメトリパス)。

均一なバッファーを使用するには、適度に最新のバージョンのGL(3.1または拡張機能、一部の古いがまだ稼働中のラップトップを除いて今日は十分に一般的)が必要であり、かなり最近のバージョンが必要です。シェーダーコード内から特定のバインディングロケーションに均一なバッファーをバインドできます(4.2;まだ一般的ではありませんが、改善されています)。とにかく指すので、それは深刻な問題というよりもAPIの匂いです。OpenGL | ESは3.0までは均一なバッファーを追加しませんでしたが、残念ながら、ほとんどの一般的なモバイルプラットフォームではまだサポートされていません。

バッファーがオプションではない場合、アクティブなシェーダーのインデックスの場所を格納するためのグローバルな場所が必要になります。glGetUniformLocationシェーダーを読み込んだ後でを使用して、既知の名前(ModelViewMatrixなど)のインデックスを検索し、これらのインデックスを保存できます。レンダーはMODEL_VIEWSetUniformラッパー関数に渡されるような列挙値をマップして、バインドされたシェーダーを調べ、インデックスを見つけ、glUniform適切に呼び出すことができます。すべてをうまくまとめた場合に各ユニフォームを個別に設定する必要があることを除いて、バッファからのクライアントコードの使用法に大きな変更はありません。

GLSLインターフェースブロックUniform Bufferオブジェクトを参照してください。


私はそれらが組み込みの方法であることを知っていました。ありがとう!
Lerp

4

これを行う最も簡単な方法は、シェーダー間で統一された名前を標準化し、描画する直前にすべてのデータを送信することです。オーバーヘッドはめちゃくちゃではありませんが、後で最適化して、更新頻度の低いユニフォームを送信しないようにすることができます。

私のゲームでこれを行う方法は、抽象Materialクラスがあることです。マテリアルは、ゲームとシェーダーの間のブリッジとして機能します。それぞれMaterialに、Shaderテクスチャなど、設定可能なさまざまなプロパティがあります。オブジェクトを描画するときは、Materialバインドされています。このBindメソッドには、GraphicsStateすべての現在のグラフィックス状態(マトリックス、ライトなど)を含むパラメーターがあります。このBindメソッドは、シェーダーとテクスチャをバインドし、すべてのユニフォームを設定しますGraphicsState

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.