OpenGLを使用してC ++でゲームを作成しています。
知らない人のために、OpenGL APIを使用して、などの多くの呼び出しをglGenBuffers行いますglCreateShader。これらの戻り値の型は、GLuint作成したものに対する一意の識別子です。作成されるものはGPUメモリ上に存在します。
GPUメモリが制限されている場合があることを考えると、複数のオブジェクトで使用されるときに同じものを2つ作成したくない場合があります。
たとえば、シェーダー。あなたは、シェーダプログラムをリンクして、あなたが持っていますGLuint。シェーダーを使い終わったら、呼び出す必要がありますglDeleteShader(またはそれに影響を与える何か)。
ここで、次のような浅いクラス階層があるとします。
class WorldEntity
{
public:
/* ... */
protected:
ShaderProgram* shader;
/* ... */
};
class CarEntity : public WorldEntity
{
/* ... */
};
class PersonEntity: public WorldEntity
{
/* ... */
};
私が今まで見たどのコードでも、すべてのコンストラクターにShaderProgram*渡して、に格納する必要がありWorldEntityます。ShaderProgramは、GLuintOpenGLコンテキストでの現在のシェーダー状態へののバインディングと、シェーダーを使用するために必要な他のいくつかの役立つことをカプセル化する私のクラスです。
私がこれで持っている問題は:
- を構築するために必要な多くのパラメーターがあります
WorldEntity(メッシュ、シェーダー、多数のテクスチャーなどがあると考えてください。これらはすべて共有できるため、ポインターとして渡されます) - どのような作成された
WorldEntityかを知る必要性をShaderProgramそれが必要 - これはおそらく、異なるエンティティに渡すもののインスタンスを知っているある種のgulp
EntityManagerクラスを必要としますShaderProgram。
つまりManager、クラスが必要なインスタンスEntityManagerとともにに自分自身を登録する必要があるかShaderProgram、switch新しいWorldEntity派生型ごとに更新する必要がある、マネージャの大物が必要なためです。
私が最初に考えたのは作成することでしたShaderManager(私は管理者が不良である、知っている)私はへの参照やポインタで渡すというクラスをWorldEntityので、彼らは何でも作成することができますクラスShaderProgramを経由して、彼らが望むShaderManagerとShaderManager、既存のトラックに保つことができShaderProgram、それができるよう、秒すでに存在するものを返すか、必要に応じて新しいものを作成します。
(私ShaderProgramはShaderProgramsの実際のソースコードのファイル名のハッシュを介してsを保存できます)
だから今:
- の
ShaderManager代わりにShaderProgramにポインタを渡しているので、まだ多くのパラメータがあります - 私はは必要ありません。
EntityManagerエンティティ自体がどのインスタンスShaderProgramを作成するかを認識しShaderManager、実際ShaderProgramのを処理します。 - しかし、今
ShaderManagerはShaderProgram、それが保持しているを安全に削除できる時期がわかりません。
だから今私は自分に参照カウントを追加しましたShaderProgramその内部を削除し、クラスGLuintを経由してglDeleteProgram、私はと離れて行いますShaderManager。
だから今:
- オブジェクトは
ShaderProgram必要なものは何でも作成できます - しかし、
ShaderProgram追跡している外部マネージャーがいないため、重複したsがあります。
最後に、私は2つの決定のうちの1つを行うようになりました。
1.静的クラス
A static classを作成するために呼び出されますShaderProgram秒。これShaderProgramは、ファイル名のハッシュに基づいてsの内部トラックを保持します。つまり、ポインタまたはShaderProgramsまたはShaderManagers への参照を渡す必要がなくなるため、パラメータが少なくなります- 作成するWorldEntitiesインスタンスのすべての知識がありますShaderProgram
この新しいstatic ShaderManagerニーズ:
- a
ShaderProgramが使用された回数のカウントを保持し、私がShaderProgramコピー可能にしない、または ShaderProgramsはそれらの参照をカウントしglDeleteProgram、カウントが0ANDであるときにのみデストラクタを呼び出し、かつが1のをShaderManager定期的にチェックしてShaderProgram破棄します。
このアプローチの欠点は次のとおりです。
問題になる可能性のあるグローバル静的クラスがあります。OpenGLコンテキストは、
glX関数を呼び出す前に作成する必要があります。したがって、潜在的に、aWorldEntityが作成され、ShaderProgramOpenGLコンテキストの作成前に作成しようとすると、クラッシュが発生する可能性があります。これを回避する唯一の方法は、ポインタ/参照としてすべてを渡すか、クエリ可能なグローバルGLContextクラスを用意するか、構築時にコンテキストを作成するクラスにすべてを保持することです。または、
IsContextCreatedチェックできるグローバルなブール値だけかもしれません。しかし、これはどこにでも醜いコードを与えることを心配しています。私が進化しているのを見ることができるのは:
Engine構築/解体の順序を適切に制御できるように、他のすべてのクラスが内部に隠されている大きなクラス。これは、ラッパー上のラッパーのように、エンジンのユーザーとエンジンの間のインターフェースコードの大きな混乱のようです- インスタンスを追跡し、必要に応じて削除する「Manager」クラス全体。これは必要悪かもしれない?
そして
- いつ実際に
ShaderProgramsをクリアするのstatic ShaderManagerですか?数分ごと?すべてのゲームループ?ShaderProgramが削除された後、新しいがWorldEntity要求した場合に、シェーダーの再コンパイルを適切に処理しています。しかし、もっと良い方法があると確信しています。
2.より良い方法
それが私がここで求めていることです
WorldEntitys を構築するためにファクトリー・クラスを実装するとします。問題の一部をシフトしていませんか?これは、WorldFactoryクラスが各WolrdEntityに正しいShaderProgramを渡す必要があるためです。