我已经在这里问过类似但有点不清楚的问题,但这次我将非常具体和直截了当。
假设我有一个演员,它抓住了一个力量。他开始使用绽放着色器发光,并在 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);
}
您会看到为了附加不同的着色器需要编写多么不同的代码。现在如果我想重新附加默认着色器怎么办?(这是着色器的附加和分离必须在运行时发生,例如:演员收集电源)。
有什么想法我可以如何有效且轻松地实现它以允许模型在运行时更改着色器?我只是期待一个好的实施/想法。各位大佬会怎么处理上面的问题呢?