OpenGL:シェーダーを配置する場所


17

私はOpenGL ES 2.0を学ぼうとしていますが、シェーダーを「管理」するための最も一般的なプラクティスは何だろうと思っています。
私がこの質問をしているのは、私が見つけた例(Android SDKで提供されているAPIデモに含まれている例など)で、通常、GLRendererクラス内のすべてが表示され、私ができるように物事をかなり分けたいからです。たとえば、OpenGL ES 1.0コードと同じように、テクスチャ付きのクワッドを描画したいときに再利用できるGLImageオブジェクト(現時点では2Dのみに焦点を当てています)。私が見つけたほとんどすべての例で、シェーダーはクラス属性として定義されています。例えば:

public class Square {

public final String vertexShader =
        "uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec4 aColor;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vColor = aColor;\n" +
        "}\n";

public final String fragmentShader =
        "precision mediump float;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_FragColor = vColor;\n" +
        "}\n";
// ...
}

これらの質問のいくつかが馬鹿げている場合は事前に謝罪しますが、以前にシェーダーを扱ったことはありません。

1)上記のコードは、シェーダー(パブリック最終クラスプロパティ)を定義する一般的な方法ですか?
2)別のShaderクラスが必要ですか?
3)シェーダーがそれらを使用するクラスの外部で定義されている場合、それらの属性の名前(たとえば、次のコードの「aColor」)をどのように知ることができますか?

colorHandle = GLES20.glGetAttribLocation(program, "aColor");

回答:


16

私はいつも(文字列で)シェーダーを定義するその方法を嫌っていました。私はテキストファイルで自分の作業を行い、読み込み時に読み込むことを好みます。文字列で定義するのはデバッグに迷惑で、私には面倒に見えます。文字列の中ではなく、入力して、あるべき形式になっているのを見るのがずっと簡単です。

また、シェーダーの読み取りやシェーダーデバッグ用のログ情報の印刷など、共通のシェーダー機能を持つ別のクラスもあります。

シェーダーが定義されている場所では、例の場合と同じように名前にアクセスできます。文字列リテラルを使用すると、これらの値は実装後に変更される可能性が低いため、シェーダーでは受け入れられます。

ただし、最終的にはあなた次第です。あなたが現在それをしている方法は、それがあなたに何の問題も引き起こしていないなら、うまく機能します。


2
シェーダーを別のファイルに保存することは、便利なシェーダーエディターを使用して完全な構文強調表示を行い、サポートしている場合はプログラムでテストする前にプレビューすることもできます。
ラセマズション

6
文字列にシェーダーを配置する唯一の本当の理由は、クイックテストとチュートリアルのためです。ファイル処理が大量の「不必要なコード」を追加する場合です。
ヤリコンパ

2
シェーダーファイルにホットリロードを実装することもできます-ゲームを再起動せずに変更をデバッグできます。Productivity ++
リオサン

私はそれらをファイルから読み取り、別のShaderクラスを持つというアイデアが好きです。それらを常に文字列で見ることは、私がそれが通常定義されている方法であるのか、単に学習目的のためであるのかわからなかったため、私を混乱させました。ありがとう!
miviclin

8

シェーダー(ひいてはマテリアル)管理は、グラフィックシステムがより複雑になり、すべてのシェーダーのハードコーディングが大量のコード複製につながることに気付くと、かなり厄介な問題になります。これを解決するいくつかの代替方法を次に示します。

  • Jari Komppaがコメントしたように、シェーダーが数個しかない小さな例では、ファイル処理を回避するために文字列としてハードコードする傾向があります
  • より良いのは、構文の強調表示と適切な書式設定が可能な個別のファイルを使用することです。これらのファイルの変更を監視し、ゲームの実行中に変更されたシェーダーをその場で適用する単純なデバッグシステムをコーディングすることもできます。
  • マテリアル数が増えると、シェーダージェネレーターがほぼ必要になります。基本的に、「フラグメントシェーダー法線マッピングスニペット」などの一般的なスニペットを定義し、目的のコンポーネントを含めることで完全なシェーダーを作成します。
    • ハードコードされた文字列スニペットを使用することもできますが、それは非常に高速になりますので、もう一度ファイルを作成することをお勧めします。
    • コードのビットを別々のファイルに(または同じ)配置するか、プリプロセッサ(または統一フラグ)を使用してubershader / supershaderを使用して、有効化/無効化することができます。

属性やユニフォーム名などについては、すべてのシェーダーで一貫した名前を使用するだけです。


シェーダーは必ず別のファイルに移動します。ありがとう!
miviclin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.