假设我有一个着色器设置为使用 3 个纹理,并且我需要渲染一些需要所有相同着色器属性的多边形,只是它只需要 1 个纹理。我注意到在我自己的显卡上,我可以简单地调用 glDisableVertexAttrib() 来禁用其他两个纹理,这样做显然会导致片段着色器接收到的禁用纹理数据全部为白色 (1.0f)。换句话说,如果我有片段着色器指令(伪代码)...
final_red = tex0.red * tex1.red * tex2.red
...无论我是否启用了 1 个、2 个或 3 个纹理,该操作都会产生所需的最终值。由此产生了一些问题:
禁用这样的预期纹理是否合法,或者我的特定显卡具有这种明显的数学保护措施是否是巧合?
“最佳实践”是创建一个单独的着色器程序,只需要单个纹理进行单个纹理渲染吗?
如果任一方法都有效,那么创建第二个着色器程序有好处吗?我认为进行 2 次 glDisableVertexAttrib() 调用比调用一次 glUseProgram() + 5-6 次 glGetUniform() 花费的时间更少,但也许 #4 解决了这个问题。
当使用 glUseProgram() 更改事件着色器程序时,我是否需要每次调用 glGetUniform... 函数来重新建立程序中每个统一的位置,或者每个预期的位置在着色器程序被释放之前保持一致?
最佳答案
禁用顶点属性不会真正禁用您的纹理,它只会给您未定义的纹理坐标。 可能会产生类似于禁用特定纹理的效果,但要正确执行此操作,您应该使用统一的或可能的子例程(如果您有同一着色器的数十种变体) )。
就禁用顶点数组状态所需的时间而言,这可能会比更改统一值慢。设置统一值并不会真正影响渲染管道状态,它们只是对内存的微小更改。同样,不断交换当前的 GLSL 程序会导致着色器缓存无效等操作,因此这也比设置统一值要昂贵得多。
如果您使用的是现代 GL 实现(GL 4.1+ 或实现 GL_ARB_separate_shader_objects
的实现),您甚至可以设置统一值而根本不需要绑定(bind) GLSL 程序,只需调用 glProgramUniform* (...)
我最关心的是你认为你需要打电话glGetUniformLocation (...)
每次设置制服的值时。 GLSL 程序中统一位置唯一发生变化的时间是链接它时。假设您不经常重新链接 GLSL 程序,则只需查询这些位置一次并永久存储它们。
关于opengl - 我真正需要多少个着色器程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27108736/