我已经问过类似但有点不清楚的问题here但这次我会非常具体并且重点突出。在运行时在同一模型上使用不同的着色器
假设我有一个演员,抓住了权力。他开始使用bloom着色器进行发光,并在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);
}
你看你需要的代码如何千差万别,以连接不同的着色器来写。现在,如果我想重新添加默认着色器,该怎么办? (这是着色器的附着和分离必须在运行时发生,例如:演员收集电源)。
任何想法如何有效和轻松地实现这个允许模型在运行时更改着色器?我只是期待着一个很好的实现/想法。你们会如何处理上述问题?
答案有点模糊(可能不正确)。你能更具体一点吗? :) – fakhir
我不是GLES专业版,但我认为你的应用程序中的某个地方设置了使用哪个着色器。 'glUseProgram()'是什么。如果你调用'glUseProgram()'并指定一个不同的程序,那么你会得到不同的'效果'。如果有什么阻止你这样做,请将其添加到问题 – MadcoreTom
那么,上述代码只是算法,而不是'确切'的代码。假定从某处使用glUseProgram()设置着色器。它可以位于渲染函数中,也可以位于外部世界中,也可以位于Geometry类中......无论调用何处,都可以保证着色器在调用渲染代码之前被正确绑定。 – fakhir