【问题标题】:GLSL boolean evaluation wackinessGLSL布尔评估古怪
【发布时间】:2014-06-15 19:13:22
【问题描述】:

我在片段着色器中使用了一个简单的开/关开关。我想将运动模糊通道的输出与未处理的输出进行比较,因此我在片段着色器中添加了一个布尔统一,如下所示:

uniform boolean blur;

我像这样激活它(基于键盘输入和一个名为 blur 的全局 int):

if ( key == 'b' ) blur = !blur;
glUseProgram( program );
glUniform1i( blur_loc, blur );

然后在着色器中用我所有的其他制服声明它:

uniform bool blur;

然后这样读:

if ( blur ) {
    FragColor = texture( color_texture, uv );
} else {
    FragColor = color/MAX_SAMPLES;
}

现在这里是有趣的部分......当我删除 if 子句时,这两个 FragColor 语句中的任何一个都可以正常工作。硬编码到 FragColor 没有模糊它看起来像这样:

使用模糊硬编码到 FragColor,如下所示:

buuuut...一旦我添加了 if 子句,就会呈现第三个(!)意外图像...看起来被夸大了,或添加了混合或其他东西...像这样:

到底发生了什么?如何添加一个布尔 if 子句导致呈现完全不同的图像?我唯一可以假设的是,存在某种内存损坏或着色器由于某种原因运行了两次(看起来像是我添加了两个图像)......可能是什么原因造成的,我在使用像傻瓜一样统一布尔值?

更新

似乎在 if 子句中,非模糊片段写入充当添加剂,而模糊片段写入正常...无论我将它们放在什么顺序。什么给出?

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 子句并只使用其他语句之一,它们会正确地写入非模糊图像或模糊图像...

FragColor = color/MAX_SAMPLES; // correctly writes a blurred image

FragColor = texture( color_texture, uv ); // correctly writes a non-blurred image

更新 2

所以我发现一些文档在条件语句中完成状态纹理采样时未定义......(下面的 cmets 之一也建议这样做)。但是,即使纹理采样发生在 if 语句之外,行为也是相同的:

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 的评论让我将 blur 的值绘制到屏幕上以确保它将屏幕变成全黑或全白(确实如此)之后,我决定尝试一个非常基本的 if-then 或者写一个蓝色片段或红色片段取决于我传入的布尔值:

if ( blur ) {
   FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
} else {
   FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
}

当然,这行得通。不过,这就是有趣的地方...

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 );
}

只有当我感兴趣的两件事都涉及到时:(

if ( blur ) {
    FragColor = texture( color_texture, uv ):
} else {
   FragColor = color/MAX_SAMPLES;
}

也许值得注意的是,变量color 也以纹理样本的形式开始了它的生命,实际上是同一个:

vec4 color = texture( color_texture, uv );

情节变厚了?

更新 4

这是完整的着色器,(基于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 );
    }

【问题讨论】:

  • 如果您将条件表达式提取到另一段代码中,然后将一个值分配给FragColor,该怎么办?还有,FragColor 变量是什么类型的?
  • FragColor 在 vec4...没有 if 子句)它按预期工作,第二个 FragColor 正确指示结果...
  • 您确定您的blur_loc 实际上是blurs 的位置,而不是color?将模糊投射到颜色上,看看是否正确。
  • 肯定的,当我抓取 *_loc 变量时,我会打印它们...color_texture_loc 是 8,blur_loc 是 9。
  • 你说的有些不对劲。 texture(color) 的意思是 texture(color_texture)?在这种情况下,仅将采样颜色除以某个常数不会产生模糊效果;那它是从哪里来的呢?奇迹不会发生在软件中(好吧,除非内存没有损坏)。

标签: opengl glsl


【解决方案1】:

我看不出你的着色器有什么问题会导致这个...

不过,我可以立即找到一种解决方法,在 blurfalse 的情况下也可能会提高性能。

我建议以这种方式重写着色器的结尾:

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;
}

这里有一些有趣的事情需要注意:

  1. 除以MAX_SAMPLES 对我来说似乎是错误的 - 你实际上多次采样你的纹理MAX_SAMPLES + 1

    • 您链接到的文章除以 MAX_SAMPLES但是它从索引 1 而不是 0 开始循环强>.

  2. 在更改此设置之前,您在 blur 无缘无故为 false 的情况下对纹理进行了 MAX_SAMPLES 次采样,然后在分支中实际执行与 color 相同的提取。

    • 总共是 11 次纹理提取(其中 10 次是间接的 -- 动态纹理坐标)。

避免点 #2 在您没有模糊的情况下应该会提高性能。因此,即使这不能解释您的根本问题,它仍然是您应该考虑的更改。

在检查了您的着色器后,我注意到了一些其他有趣但基本上不相关的事情:

  1. 我假设这些PV 矩阵实际上是您的投影和视图矩阵的逆矩阵?否则,这一切都没有多大意义。我会考虑为制服使用一个名称,使其明显被反转,因为对我来说P[rojection] 表示从视图空间转换到剪辑空间而不是相反的矩阵。

  2. 您链接到的文章在 NDC 空间中进行速度计算。这意味着你在事情上走错了方向……你想重新投影世界位置。我相信如果您使用透视投影,这可能是一个问题,如果使用世界空间完成,模糊将与文章不一致(因为该坐标空间未考虑透视缩放)。

【讨论】:

  • 当然,优化编译器最终可能会按照这些思路做一些事情。但与此同时,这整个问题听起来像是编译器在不破坏整个事物的情况下正确优化第二个分支的能力的问题。
猜你喜欢
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多