GLSL布尔值评估的古怪性 [英] GLSL boolean evaluation wackiness
问题描述
我花了很长时间在片段着色器中使用一个简单的开/关开关.我想将运动模糊处理的输出与未处理的输出进行比较,因此我向片段着色器添加了布尔统一,如下所示:
I am having quite a time with a simple on/off switch in my fragment shader. I want to compare the output of a motion-blur pass with the unprocessed output, so I have added a boolean uniform to the fragment shader like such:
uniform boolean blur;
我激活它(基于键盘输入和一个称为模糊的全局int),如下所示:
I activate it (based on keyboard input and a global int called blur) like such:
if ( key == 'b' ) blur = !blur;
glUseProgram( program );
glUniform1i( blur_loc, blur );
,然后在着色器中将其与我的所有其他制服一起声明,如下所示:
and then in the shader it is declared with all my other uniforms like this:
uniform bool blur;
阅读如下:
if ( blur ) {
FragColor = texture( color_texture, uv );
} else {
FragColor = color/MAX_SAMPLES;
}
现在这是有趣的部分...当我删除if子句时,这两个FragColor语句中的任何一个都能很好地工作.硬编码到FragColor而不模糊,它看起来像这样:
Now here is the interesting part... either of those two FragColor statements works fine on its own, when I remove the if-clause. hardcoded to the FragColor without blur it looks like this:
以模糊方式硬编码到FragColor中,它看起来像这样:
hardcoded to the FragColor with blur it looks like this:
buuuut ...一旦我添加了if子句,就会渲染第三个(!)意外图像...看起来过分夸张,或添加了混合或类似的东西...
buuuut... once I add the if-clause a third (!) unexpected image is rendered... what looks to be overblown, or additive blended or something... like this:
到底发生了什么?如何添加布尔if子句导致呈现完全不同的图像?我唯一可以假设的是,发生某种内存损坏,或者由于某种原因着色器运行了两次(看起来就像我同时添加了两个图像一样)...可能是什么原因造成的,我在使用吗?笨蛋像傻瓜吗?
What on earth is happening? how is adding a boolean if-clause causing a whole different image to be rendered? the only thing I can posit is that there is some sort of memory corruption going on OR the shader is running twice for some reason (it sort of looks like if I added both images)... what could be causing this, am I using uniform bool like a fool?
更新
似乎在if子句中,不模糊的片段写起了加法的作用,而模糊的片段写起了正常的作用……无论我将它们按什么顺序排列.给出了什么?
It seems that when in the if-clause, the non-blurred fragment write acts as an additive and the blurred fragment write acts normally... no matter what order I put them in. What gives?
if ( blur ) {
FragColor = texture( color_texture, uv ); // writes an odd compound image
} else {
FragColor = color/MAX_SAMPLES; // correctly writes a blurred image
}
或
if ( blur ) {
FragColor = color/MAX_SAMPLES; // correctly writes a blurred image
} else {
FragColor = texture( color_texture, uv ); // writes an odd compound image
}
再次,如果我摆脱了if子句,而只使用其他语句之一,它们将正确地写入非模糊图像或模糊图像...
again, if I get rid of the if-clause and use just one of the other statements, they correctly write either the non-blurred image or the blurred image...
FragColor = color/MAX_SAMPLES; // correctly writes a blurred image
或
FragColor = texture( color_texture, uv ); // correctly writes a non-blurred image
更新2
因此,我发现一些文档表明在条件语句中进行状态纹理采样时未定义...(下面的注释之一也表明了这一点).但是,即使纹理采样发生在if语句之外,其行为也相同:
So I have found some docs that state texture sampling is undefined when done in a conditional statement... (one of the comments below also suggested this). However, the behavior is the same even when the texture sampling happens outside the if statement:
vec4 sampled_color = texture( color_texture, uv );
if ( blur ) {
FragColor = color/MAX_SAMPLES; // correctly writes a blurred image
} else {
FragColor = sampled_color; // writes an odd compound image
}
更新3
在keltar的评论让我在屏幕上绘制了模糊的值以确保它将屏幕变成全黑或全白(确实如此)之后,我决定尝试一个非常基本的if-then,然后将其写为蓝色片段或红色片段,具体取决于我传入的布尔值:
After keltar's comment made me draw the value of blur to the screen to make sure it would turn the screen all black or all white (it did), I decided to try a very basic if-then that would either write a blue fragment or a red fragment depending on my passed-in-boolean value:
if ( blur ) {
FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
} else {
FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
}
当然可以.这是有趣的地方...
of course, this worked. here is where it gets interesting though...
if ( blur ) {
FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
} else {
FragColor = color/MAX_SAMPLES;
}
也可以......
if ( blur ) {
FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
} else {
FragColor = texture( color_texture, uv );
}
只有当我感兴趣的两件事都涉及时:(
It is only when the two things I am interested in are both involved :(
if ( blur ) {
FragColor = texture( color_texture, uv ):
} else {
FragColor = color/MAX_SAMPLES;
}
也许值得一提的是,变量color
也是从纹理样本开始的,实际上是一样的:
Perhaps it is worth noting that the variable color
begins its life as a texture sample as well, in fact the very same one:
vec4 color = texture( color_texture, uv );
剧情变厚了吗?
更新4
这是完整的着色器,(基于GPU GEMS 3的第27章)
here is the full shader, (based on chapter 27 of GPU GEMS 3)
#version 150
in vec2 vUV;
out vec4 FragColor;
uniform sampler2D depth_tiu;
uniform sampler2D color_tiu;
uniform mat4 P;
uniform mat4 V;
uniform mat4 V_prev;
uniform bool blur;
void main() {
float z_over_w = texture( depth_tiu, vUV ).r;
vec4 view_pos = vec4( 2*vUV.x - 1, 2*(1 - vUV.y) - 1, z_over_w, 1.0 );
vec4 D = P * V * view_pos;
vec4 world_pos = D/D.w;
vec4 previous_world_pos = P * V_prev * view_pos;
previous_world_pos /= previous_world_pos.w;
vec2 velocity = vec2((world_pos - previous_world_pos)/2.0);
velocity = clamp( velocity, vec2(-0.001, -0.001), vec2(0.001, 0.001) );
int MAX_SAMPLES = 10;
vec4 color = texture( color_tiu, vUV );
vec2 write_UV = vUV;
write_UV += velocity;
for ( int i = 0; i < MAX_SAMPLES; ++i, write_UV += velocity ) {
vec4 curr_color = texture( color_tiu, write_UV );
color += curr_color;
}
if ( blur ) {
FragColor = color/MAX_SAMPLES;
} else {
FragColor = texture( color_tiu, vUV );
}
推荐答案
我看不到您的着色器有任何立即导致此问题的错误.
但是,我可以立即发现一种解决方法,在blur
为 false 的情况下,它也可能会提高性能.
I cannot see anything immediately wrong with your shader that would cause this...
I can, however, immediately spot a work-around for it that will probably also improve performance in the case when blur
is false.
FragColor = texture( color_tiu, vUV );
if ( blur ) {
const int MAX_SAMPLES = 10;
vec2 write_UV = vUV + velocity;
for ( int i = 0; i < MAX_SAMPLES; ++i, write_UV += velocity ) {
FragColor += texture( color_tiu, write_UV );
}
FragColor /= MAX_SAMPLES;
}
在这里有几点有趣的事情要注意:
-
用
MAX_SAMPLES
划分似乎对我来说是错误的-您实际上对纹理MAX_SAMPLES + 1
进行了多次采样.
Dividing by
MAX_SAMPLES
seems wrong to me - you actually sample your textureMAX_SAMPLES + 1
many times.
- 您链接的文章除以
MAX_SAMPLES
, 但 ,它的循环从索引 1 而不是 0 .
在更改此设置之前,您无缘无故地在blur
为 false 的情况下对纹理进行了MAX_SAMPLES
采样,然后实际上在color
中执行了与color
相同的提取.分支.
Prior to changing this you sampled your texture MAX_SAMPLES
times in the case where blur
was false for no reason and then actually performed the same fetch as color
in the branch.
- 总共是 11 个纹理获取(其中10个是间接获取的-动态纹理坐标),没有任何原因.
- Altogether that was 11 texture fetches (10 of which were indirect -- dynamic texture coordinates) for no reason.
避开点#2 可以在不模糊的情况下提高性能.因此,即使这不能解释您的根本问题,仍然是您应该考虑的更改.
Avoiding point #2 should improve performance in the case where you are not blurring. Thus, even if this does not explain your underlying problem, it is still a change you should consider.
-
我假设这些
P
和V
矩阵实际上是投影矩阵和视图矩阵的逆矩阵?否则,这都没有多大意义.我会考虑为制服使用一个名称,以使制服很明显被颠倒,因为对我而言,P[rojection]
表示从视图空间转换为剪贴空间而不是相反的矩阵.
I assume these
P
andV
matrices are actually inverses of your projection and view matrices? Otherwise none of this makes much sense. I would consider using a name for the uniforms that makes it obvious they are inverted, because to meP[rojection]
means a matrix that transforms from view-space to clip-space rather than the other way around.
链接到的文章在NDC空间中进行速度计算.这意味着您在事情上走错了方向……您想重新设计世界位置.我相信如果您使用透视投影,这可能是个问题,如果使用世界空间,则模糊效果将与文章不一致(因为透视缩放未考虑到该坐标空间中).
The article you linked to does the velocity computation in NDC space. That means you have gone the wrong direction with things... you would want to re-project the world position. I believe this could be an issue if you are using perspective projection, the blur would not be consistent with the article if done using world-space (because perspective scaling is not factored into that coordinate space).
这篇关于GLSL布尔值评估的古怪性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!