我已經問過類似但有點不清楚的問題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