我一直在阅读很多关于制服的文章,如果这些陈述涉及分支以改变大型着色器"超级着色器"的行为.我开始使用超级着色器(opengl lwjgl),但后来我意识到,在没有统一if语句的单独着色器中,在片段着色器中添加if语句设置简单计算的简单操作会使我的fps减少5.我没有为我的fps限制设置任何上限,它只是尽可能快地刷新.我即将添加法线贴图和parrallax贴图,我可以看到两条路线:
优步顶点着色器:
#version 400 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 textureCoords;
layout(location = 2)in vec3 normal;
**UNIFORM float RenderFlag;**
void main(void){
if(RenderFlag ==0){
//Calculate outVariables for normal mapping to the fragment shader
}
if(RenderFlag ==1){
//Calcuate outVariables for parallax mapping to the fragment shader
}
gl_Position = MVPmatrix *vec4(position,1);
}
Run Code Online (Sandbox Code Playgroud)
优步片段着色器:
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 textureCoords;
layout(location = 2)in vec3 normal;
**UNIFORM float RenderFlag;**
**UNIFORM float reflectionFlag;** // if set either of the 2 render modes
will have some reflection of the skybox added to it, like reflective
surface.
void main(void){
if(RenderFlag ==0){
//display normal mapping
if(reflectionFlag){
vec4 reflectColor = texture(cube_texture, ReflectDirR) ;
//add reflection color to final color and output
}
}
if(RenderFlag ==1){
//display parrallax mapping
if(reflectionFlag){
vec4 reflectColor = texture(cube_texture, ReflectDirR) ;
//add reflection color to final color and output
}
}
gl_Position = MVPmatrix *vec4(position,1);
}
Run Code Online (Sandbox Code Playgroud)
这个(对我来说)的好处是简单的流程,但使整个程序更复杂,我面临丑陋的嵌套if语句.此外,如果我想完全避免if语句,我需要4个单独的着色器,一个用于处理每个可能的分支(正常无反射:正常反射:Parrallax w/o反射:Parrallax with reflection)仅适用于一个特征,反射.
1:GLSL是否执行分支和后续分支并计算BOTH函数然后输出正确的分支?
2:我应该删除if语句而不是反射的统一标志,而不是无论如何计算反射颜色,如果它是一个相对较小的操作,我将它添加到最终颜色
finalColor = finalColor + reflectionColor * X
where X = a uniform variable, if none X == 0, if Reflection X==some amount.
Run Code Online (Sandbox Code Playgroud)
首先,让我指出 GL4 添加了子例程,这些子例程是您所讨论的这两件事的组合。但是,除非您使用单个基本着色器的大量排列,并且在一帧期间多次交换(如果您在前向渲染引擎中有一些动态材质系统,则可能会这样做),否则子例程实际上并不能带来性能优势。我在自己的工作中投入了一些时间和精力,并且在一个特定的硬件/驱动程序组合上得到了有价值的改进,而在大多数其他组合上没有明显的变化(好或坏)。
为什么我要提出子程序?主要是因为您正在讨论什么相当于微观优化,而子例程是一个很好的例子,说明了为什么在开发结束之前投入大量时间思考这一点是不值得的。如果您正在努力满足某些性能指标,并且您已将所有高级优化策略从列表中划掉,那么您可以担心这个问题。
也就是说,几乎不可能回答 GLSL 如何执行着色器。它只是一种高级语言;自从 GLSL 创建以来,底层硬件架构已经发生了多次变化。最新一代的硬件具有实际的分支预测和一些 GLSL 1.10 级硬件从未有过的相当复杂的线程引擎,其中一些现在实际上是通过计算着色器直接公开的。
您可以运行这些数字来查看哪种策略最适合您的硬件,但我认为您会发现这是旧的微优化困境,您甚至可能无法获得足够的可测量的性能差异来猜测采用哪种方法。请记住,“Uber 着色器”由于多种原因而具有吸引力(并非所有与性能相关),最重要的是,您可能需要批处理的绘制命令越来越少且不太复杂。如果性能没有明显差异,请考虑更简单且更易于实施/维护的设计。