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