我正在尝试制作一个可以关闭纹理和/或着色的glsl着色器(我希望能够为纹理着色)。我可以通过执行glDisableVertexAttribArray(x)
来禁用属性,但我想知道着色器中的值会是什么样子。它们会是0
吗?
此外,是否有方法检查着色器代码中是否启用了属性?我想到了一个统一的(可能是int
)来存储标志并在着色器中测试它们,但这需要if
语句,我想我听说不建议这样做。
以下是我的着色器,以防您想引用它们,我目前正在处理我所说的int
标志。
顶点着色器:
#version 450
layout(location=0) uniform mat4 projection_matrix;
layout(location=1) uniform mat4 view_matrix;
layout(location=2) uniform mat4 model_matrix;
// 0b0000 0000 0000 0 unused
// 0 textures
// 0 colors
// 0 2d/3d
layout(location=3) uniform uint mode;
layout(location=0) in vec4 vert_tex_coord;
layout(location=1) in vec4 vert_color;
layout(location=2) in vec3 vert_2_position;
layout(location=3) in vec3 vert_3_position;
out vec4 vert_frag_color;
out vec2 vert_frag_tex_coord;
vec4 transform(vec4 v)
{
return projection_matrix * view_matrix * model_matrix * v;
}
void main()
{
if ((mode & 1) > 0)
{
gl_Position = transform(vec4(vert_3_position, 1.0));
}
else
{
gl_Position = transform(vec4(vert_2_position, 0.0, 1.0));
}
if ((mode & 2) > 0)
{
vert_frag_color = vert_color;
}
if ((mode) & 4) > 0)
{
vert_frag_tex_coord = vert_tex_coord;
}
}
片段着色器:
#version 450
layout(location=3) uniform uint mode;
uniform sampler2D texture_0;
in vec4 vert_frag_color;
out vec2 vert_frag_tex_coord;
out vec4 frag_color;
void main()
{
if ((mode & 2) > 1)
{
frag_color = vert_frag_color;
}
if ((mode) & 4) > 1)
{
frag_color = texture(texture_0, vert_frag_tex_coord);
}
}
我可以通过执行
glDisableVertexAttribArray(x)
来禁用属性,但是我想知道着色器中的值会是什么样子。他们会吗是0
?
不,实际上,每个属性的"当前"值都是全局GL状态的一部分。可以通过glVertexAttrib*()
函数族为禁用阵列的每个属性设置值。这里有一个小转折:每当您在启用某个属性数组并随后禁用该属性数组的情况下绘制某个东西时,该属性的当前值将是未定义的,因此您必须再次通过glVertexAttrib*()
重新指定它。
代码中的以下构造根本没有意义:
if ((mode & 1) > 1) { gl_Position = transform(vec4(vert_3_position, 1.0)); } else { gl_Position = transform(vec4(vert_2_position, 0.0, 1.0)); }
mode & 1
将是1或0,因此比较>1总是错误的。但是,根本不需要这种模式。如果未指定所有元素,GL将自动将输入属性向量扩展到表单(0,0,0、1)。所以使用就足够了
in vec4 vert_position;
// ...
gl_Position = transform (vert_position);
您只需在glVertexAttribPointer()
调用中指定1、2、3或4个组件,它就会按预期工作。习语in vec3 position; /* ... */ matrix * vec4(position, 1.0);
通常用于教程中,但根本不需要。不过,有人可能会说,这使实际发生的事情更加明确。
此外,是否有一种方法可以检查着色器代码?
不,没有。每个属性总是有一些当前值。是否来自数组与着色器完全无关。
我想到了一个统一的(可能是
int
)来存储标志并在着色器中测试它们,但这需要if
语句,我想我听说不建议这样做。
好吧,基于一致值的分支仍然会产生一致的控制流,所以这并不是可能发生的最糟糕的事情。但它不会没有开销。如果它是值得的,那就取决于你的场景的实际要求。使用不同的着色器并在它们之间切换可能会更好。但这一切都取决于会发生多少这样的状态切换,以及切换之间每个着色器会做多少工作,还取决于需要多少着色器组合。这是您应该进行基准测试/评测的内容,最好是跨不同的GL实现。