0

私はすでに同様の質問をしましたが、ここでは少し不明確ですが、今回は非常に具体的で要点を述べます。

パワーアップをつかむ俳優がいるとします。彼はブルーム シェーダを使用して光り始め、10 秒後に通常の状態に戻り、デフォルト シェーダを再び取り付けます。質問は基本的に次のように要約されます。

実行時に同じモデルで異なるシェーダーを使用する方法は?

次の非常に単純な例を検討してください。

デフォルトのシェーダー:

attribute vec4 Position;
uniform mat4 ModelViewProjMatrix;

void main(void)
{
    gl_Position = ModelViewProjMatrix * Position;
}

RendererGLES20 内のレンダリング コードは次のようになります。

void RendererGLES20::render(Model * model)
{
    glUniformMatrix4fv(mvpUniform, 1, 0, &mvpMatrix);
    GLuint positionSlot = glGetAttribLocation(_program, "Position");
    glEnableVertexAttribArray(positionSlot);

    // interleaved data, But for now we are ONLY using the positions, ignoring texture, normals and colours.
    const GLvoid* pCoords = &(model->vertexArray[0].Position[0]);
    glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, pCoords);

    glDrawArrays(GL_TRIANGLES, 0, model->vertexCount);

    glDisableVertexAttribArray(positionSlot);
}

簡単です!ここで、アクターがパワーアップし、次のクレイジー シェーダーが適用されたとします。

クレイジー シェーダー:

attribute vec4 Position;
attribute vec4 SourceColor;
attribute vec2 Texture;
attribute vec4 Normal;
attribute vec2 tempAttrib0;
attribute vec2 tempAttrib1;

// A bunch of varying but we don't need to worry about these for now                                           
varying vec4 .........;
varying .........;

uniform mat4 MVPMatrix;
uniform vec2 BloomAmount;
uniform vec2 BloomQuality;
uniform vec2 BloomSize;
uniform vec2 RippleSize;
uniform vec2 RippleAmmount;
uniform vec2 RippleLocation;
uniform vec2 deltaTime;
uniform vec2 RippleMaxIterations;

void main(void)
{
    // Some crazy voodoo source code here...
    // .........
    gl_Position = ..............;
}

ご覧のとおり、このシェーダーをモデルにアタッチするには、実際のレンダラー ソース コードを次のように変更する必要があります。

void RendererGLES20::render(Model * model)
{
    glUniformMatrix4fv(mvpUniform, 1, 0, ....);
    glUniformMatrix4fv(bloomAmountUniform, 1, 0, ....);
    glUniformMatrix4fv(bloomQualityUniform, 1, 0, ....);
    glUniformMatrix4fv(bloomSizeUniform, 1, 0, ....);
    glUniformMatrix4fv(rippleSizeUniform, 1, 0, ....);
    glUniformMatrix4fv(rippleAmountUniform, 1, 0, ....);
    glUniformMatrix4fv(rippleLocationUniform, 1, 0, ....);
    glUniformMatrix4fv(rippleMaxIterationsUniform, 1, 0, ....);
    glUniformMatrix4fv(deltaTimeUniform, 1, 0, ....);

    GLuint positionSlot = glGetAttribLocation(_program, "Position");
    GLuint sourceColorSlot = glGetAttribLocation(_program, "SourceColor");
    GLuint textureSlot = glGetAttribLocation(_program, "Texture");
    GLuint normalSlot = glGetAttribLocation(_program, "Normal");
    GLuint tempAttrib0Slot = glGetAttribLocation(_program, "TempAttrib0");
    GLuint tempAttrib1Slot = glGetAttribLocation(_program, "TempAttrib1");

    glEnableVertexAttribArray(positionSlot);
    glEnableVertexAttribArray(sourceColorSlot);
    glEnableVertexAttribArray(textureSlot);
    glEnableVertexAttribArray(normalSlot);
    glEnableVertexAttribArray(tempAttrib0Slot);
    glEnableVertexAttribArray(tempAttrib1Slot);

    // interleaved data
    const GLvoid* pCoords = &(model->vertexArray[0].Position[0]);
    const GLvoid* sCoords = &(model->vertexArray[0].SourceColor[0]);
    const GLvoid* tCoords = &(model->vertexArray[0].Texture[0]);
    const GLvoid* nCoords = &(model->vertexArray[0].Normal[0]);
    const GLvoid* t0Coords = &(model->vertexArray[0].TempAttrib0[0]);
    const GLvoid* t1Coords = &(model->vertexArray[0].TempAttrib1[0]);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
    glVertexAttribPointer(sourceColorSlot, 4, GL_FLOAT, GL_FALSE, stride, sCoords);
    glVertexAttribPointer(textureSlot, 2, GL_FLOAT, GL_FALSE, stride, tCoords);
    glVertexAttribPointer(normalSlot, 4, GL_FLOAT, GL_FALSE, stride, nCoords);
    glVertexAttribPointer(tempAttrib0Slot, 3, GL_FLOAT, GL_FALSE, stride, t0Coords);
    glVertexAttribPointer(tempAttrib1Slot, 2, GL_FLOAT, GL_FALSE, stride, t1Coords);

    glDrawArrays(GL_TRIANGLES, 0, model->vertexCount);

    glDisableVertexAttribArray(positionSlot);
    glDisableVertexAttribArray(sourceColorSlot);
    glDisableVertexAttribArray(textureSlot);
    glDisableVertexAttribArray(normalSlot);
    glDisableVertexAttribArray(tempAttrib0Slot);
    glDisableVertexAttribArray(tempAttrib1Slot);
}

異なるシェーダーをアタッチするために、非常に異なるコードを記述する必要があることがわかります。デフォルトのシェーダを再度アタッチしたい場合はどうすればよいですか? (これは、シェーダーのアタッチとデタッチが実行時に行われる必要があります。例: アクターがパワーアップを収集)。

これを効率的かつ簡単に実装して、モデルが実行時にシェーダーを変更できるようにする方法はありますか? 素敵な実装/アイデアを楽しみにしています。皆さんなら、上記の問題をどのように処理しますか?

4

2 に答える 2

0

詳細に入る前に、まずいくつかの精神的な障害を取り除きましょう。OpenGL はシーン グラフではありません。シーンをフィードしないと、モデル全体などがレ​​ンダリングされます。OpenGL は、正直なところ、OS が提供する紙に描画する鉛筆です。

OpenGL は、ある種のプログラム制御の描画ツールであると考える必要があります。読み進める前に、お気に入りの画像操作プログラム (Photoshop、GIMP、Krita など) を開いて、素敵な絵を描いてみることをお勧めします。レイヤーをコピーしてフィルターを適用し、元のレイヤーに重ね​​て目的の効果を得るなどです。

これは、OpenGL のプログラミング、特にシェーダー効果の実行に関して考える方法です。

これを分解してみましょう:

パワーアップをつかむ俳優がいるとします。

このためには、アクターのモデルとアニメーションが必要です。これはBlenderのようなツールを使ってアーティストによって行われます。

彼はブルーム シェーダーを使用して光り始めます

グローは通常、元のモデルにオーバーレイされる単なる追加パスです。その Photoshop モデルを頭の中に戻してください。まず、イルミネーション シェーダーを使用してモデルを描画します。ModelクラスとPhongTechniquqクラスを持っていると仮定しましょう。これらはTechniqueクラスから派生したもので、描画するモデルにフィードするインターフェイスを提供します。

class Model;
class ModelState;

class Technique {
    drawModel(Model const *Model, ModelState const *state, /*...*/);
};

/* technique that renders models using a phong illumination model */
class PhongTechnique {
    drawModel(Model const *Model, ModelState const *state, /*...*/);
}

そして、ブルーム効果のために、別のテクニック クラスがあります。

/* technique that renders models using a bloom */
class BloomTechnique {
    drawModel(Model const *Model, ModelState const *state, /*...*/);
}

10 秒後に通常の状態に戻り、デフォルトのシェーダーを再びアタッチします。

したがって、ゲームのアニメーション ループで、モデルに出くわします。アニメーションデータが添付されています。

class AnimationElement {
    float timeStart();
    float timeStop();
    float X(float T);
}

class Model {
    vector<AnimationElement> animation_elements;
    ModelState animate(float T);
}

モデル状態では、使用する効果のフラグがいくつかあります。したがって、全体的な描画機能で

drawscene(float T)
{
    PhongTechnique phong;
    BloomTechnique bloom;

    foreach(m in models) {
        ModelState mstate = m.animate(T);

        if(mstate.phong_pass)
            phong.drawModel(m, mstate, ...);

        if(mstate.bloom_pass)
            bloom.drawModel(m, mstate, ...);

    }
}

さまざまな Technique クラスの実装内で、適切なシェーダーに切り替え、頂点属性データを設定するなどして、モデルをレンダリングします。または正確に言うと、描画プロセスを最適化するために、後で少し順序を変更する描画バッチのリストを埋めることになります。

実際のゲーム エンジンを調べたい場合: Id Software は Doom3 および Doom3-BFG エンジンの完全なソース コードをリリースしましたが、後者には最新の OpenGL-3 コードパスがありました。

于 2013-07-04T09:19:43.260 に答える