私はすでに同様の質問をしましたが、ここでは少し不明確ですが、今回は非常に具体的で要点を述べます。
パワーアップをつかむ俳優がいるとします。彼はブルーム シェーダを使用して光り始め、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);
}
異なるシェーダーをアタッチするために、非常に異なるコードを記述する必要があることがわかります。デフォルトのシェーダを再度アタッチしたい場合はどうすればよいですか? (これは、シェーダーのアタッチとデタッチが実行時に行われる必要があります。例: アクターがパワーアップを収集)。
これを効率的かつ簡単に実装して、モデルが実行時にシェーダーを変更できるようにする方法はありますか? 素敵な実装/アイデアを楽しみにしています。皆さんなら、上記の問題をどのように処理しますか?