1

OpenGL ES 2.0 (今のところ iOS) を使用して 2D ゲーム エンジンを作成しようとしています。Objective C でアプリケーション レイヤーを作成し、C++ で別の自己完結型 RendererGLES20 を作成しました。レンダラーの外部で GL 固有の呼び出しは行われません。それは完全に機能しています。

しかし、シェーダーを使用する場合、いくつかの設計上の問題があります。各シェーダーには、メインの描画呼び出し (この場合は glDrawArrays) の直前に設定する必要がある独自の属性とユニフォームがあります。たとえば、ジオメトリを描画するには、次のようにします。

void RendererGLES20::render(Model * model)
{
    // Set a bunch of uniforms
    glUniformMatrix4fv(.......);
    // Enable specific attributes, can be many
    glEnableVertexAttribArray(......);
    // Set a bunch of vertex attribute pointers:
    glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, m->pCoords);

    // Now actually Draw the geometry
    glDrawArrays(GL_TRIANGLES, 0, m->vertexCount);

    // After drawing, disable any vertex attributes:
    glDisableVertexAttribArray(.......);
}

ご覧のとおり、このコードは非常に厳格です。波及効果などの別のシェーダーを使用する場合、追加のユニフォーム、頂点属性などを渡す必要があります。つまり、新しいシェーダーを組み込むためだけに RendererGLES20 レンダリング ソース コードを変更する必要があります。

シェーダー オブジェクトを完全に汎用にする方法はありますか? たとえば、シェーダー オブジェクトを変更したいだけで、ゲーム ソースの再コンパイルを気にしない場合はどうすればよいでしょうか? レンダラーをユニフォームや属性などにとらわれないようにする方法はありますか? ユニフォームにデータを渡す必要がありますが、それを行うのに最適な場所はどこですか? モデルクラス?モデル クラスはシェーダー固有のユニフォームと属性を認識していますか?

以下は、Actor クラスを示しています。

class Actor : public ISceneNode
{
    ModelController * model;
    AIController * AI;
};

モデル コントローラ クラス: class ModelController { class IShader * shader; int textureId; vec4 色合い; 浮動小数点アルファ; struct Vertex * vertexArray; };

シェーダー クラスには、シェーダー オブジェクト、サブルーチンのコンパイルとリンクなどが含まれています。

Game Logic クラスでは、実際にオブジェクトをレンダリングしています。

void GameLogic::update(float dt)
{
    IRenderer * renderer = g_application->GetRenderer();

    Actor * a = GetActor(id);
    renderer->render(a->model);
}

Actor は ISceneNode を拡張しますが、まだ SceneGraph の実装を開始していないことに注意してください。この問題が解決したらすぐに実行します。

これを改善する方法はありますか?関連するデザインパターンなどは?

4

4 に答える 4

4

シェーダーの要点は具体的であることです。ジェネリック API とステート マシンのインフレーションは、長い間 OpenGL を汚染していました (OpenGL-1.5 glTexEnv を見てください)。最新の OpenGL (v3 以降) の要点は、この汎用性を取り除くことでした。これにより、シェーダーを目の前のタスクに合わせて簡単に調整できるようになりました。シェーダーを、それを使用するレンダラー コードとは別のものと考えないでください。実際、シェーダーとクライアント側のレンダラー コードは補完的であり、通常は連携して開発されます。

于 2013-07-03T11:37:59.370 に答える
0

アトリビュートやユニフォームが変更されていない場合は、C++ コードを再コンパイルすることなくシェーダーを変更できます。これを行うには、テキスト ファイルからシェーダー コードをglShaderSource読み込んでコンパイルするか、コンパイル済みのバイナリ ファイルをglShaderBinary.

さまざまなレンダリング方法をカプセル化するために、RendererGLES20 から継承するさまざまなレンダラーを使用できます。そうすれば、シェーダーが必要とするアトリビュートとユニフォームをレンダラーだけが知る必要があります。

class RendererGLES20
{
public:
    virtual void render(Model * model) = 0;

    // ...
}

class RippleRenderer : public RendererGLES20
{
    virtual void render(Model * model);
    // ...
}

class BlinnPhongRenderer : public RendererGLES20
{
    virtual void render(Model * model);
    // ...
}

class CartoonRenderer : public RendererGLES20
{
    virtual void render(Model * model);
    // ...
}
于 2013-07-03T13:02:39.287 に答える