【问题标题】:WebGL fragment shader not branching correctly on if statementWebGL 片段着色器在 if 语句上没有正确分支
【发布时间】:2016-05-02 04:03:42
【问题描述】:

我正在开发一个实现阴影映射的 WebGL 程序。在计算每个片段的深度值之后,我在最后有一个 if 语句,它根据片段是否在阴影中计算光照。

gl_FragColor = vec4(calcLighting(light0, eye_dir, eye_dir_norm, normal), 1);
if (light_tex_coord.z - depth <= 0.0) {
  gl_FragColor += vec4
      ( calcLighting(light1, eye_dir, eye_dir_norm, normal)
      , 0.0
      );
}

其中depth 是阴影贴图的深度,light_tex_coord 是片段在light1 的场景空间中的位置。 light1 是围绕模型旋转的点光源,light0 是静态定位在相机上的点光源。

这里的问题是 if 分支从未被采用,所以场景只应用了light0。我检查了depthlight_tex_coordcalculateLighting 工作正常。

但奇怪的是,将上面的代码替换为以下代码:

if (light_tex_coord.z - depth <= 0.0) {
  gl_FragColor = vec4(0,1,0,1);
} else {
  gl_FragColor = vec4(1,0,0,1);
}

使阴影区域正确绘制为红色,而未阴影区域绘制为绿色。也就是说,分支被正确评估。用这个替换它:

gl_FragColor = vec4(calcLighting(light0, eye_dir, eye_dir_norm, normal), 1);
gl_FragColor += vec4
    ( calcLighting(light1, eye_dir, eye_dir_norm, normal)
    , 0.0
    );

导致正确计算光照(但没有阴影)。看来,当我在 if 语句中调用更昂贵的 calcLighting 函数时,它甚至都懒得拿它。

此外,我尝试了多种方式应用照明,包括使用clamp 函数;总是做加法并使用三元运算符将第二个 calcLighting 调用乘以 1 或 0,并以不同的方式安排我的 if 语句。似乎没有任何效果。

关于 webgl 中的分支是如何工作的,我有什么遗漏吗?

【问题讨论】:

  • 您是否尝试过将颜色累积到一个单独的vec4 变量并gl_FragColor 分配一次该另一个变量的值。应该支持在着色器中多次写入gl_FragColor 以及读取它的值(这是实现+= 所必需的),但从所有方面来看,这个问题似乎与给定的这些操作中的一个或两个有关你的控制流。
  • 我尝试用累加器vec4 acc; 替换上述sn-ps 中gl_FragColor 的所有实例。我只在着色器末尾分配了gl_FragColor = acc; 在上述任何情况下都没有变化。
  • 能否提供完整的 fs 代码?另外,如果您将代码更改为gl_FragColor += vec4( calcLight(..), 1.0 ),会有什么不同吗? [注意 1.0 alpha 值]
  • 将 alpha 从 0.0 更改为 1.0 无效。这是一大块代码,所以我把它放在pastebin上。顶点着色器:pastebin.com/XLYSwvL7 片段着色器:pastebin.com/bYdvuRjj 有问题的 sn-p 来自片段着色器的底部。
  • 由于这是 WebGL,如果您可以创建一个页面,如果我们设法重现错误,我们可以在其中尝试/更改内容,这将很有帮助。这似乎是驱动程序问题。

标签: opengl-es glsl webgl shader


【解决方案1】:

也许 WebGl 上下文不支持深度。然后使用它的表达式将被忽略。

您可以使用 getContextAttributes() 进行检查

【讨论】:

  • 在我的 javascript 代码中,我检查深度扩展,如果不存在,则将深度值写入颜色缓冲区。无论如何,我测试过的浏览器都支持深度扩展。
【解决方案2】:

你有没有考虑过像这样真正激进的东西,而不是分支:

gl_FragColor += vec4 (
    calcLighting(light1, eye_dir, eye_dir_norm, normal)
    , 0.0
    ) * abs (min (sign (light_tex_coord.z - depth), 0.0));

这不是世界上最漂亮的解决方案,但它可能会让你得到更多符合你所寻找的东西。它基本上采用您的light_tex_coord.z - depth &lt;= 0.0 条件表达式并将其转换为一个不错的浮点 0.01.0,您可以将光照乘以 keep em> 或 discard 分支结果。在引入动态流控制之前,着色器使用的工作方式。

【讨论】:

  • 这个主意不错,可惜我用的时候好像没什么效果。
【解决方案3】:

主题是 2 岁,但这是我的 2 美分:

我遇到了类似的问题,在网上找到一个页面,里面有一个讨论,里面有以下句子:

[...] (除非你在有条件的情况下做一些疯狂的事情,比如图像写入 块)。 [...]

所以我尝试将像素颜色放在一个临时变量中

vec4 col;

本地到main(),在“if”语句中我只修改col,并且只在最后设置像素颜色:

gl_FragColor = col;

这解决了我的问题。当然,它可能需要烦人的额外编程才能让流程在每种情况下都到达最后一行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2012-12-20
    • 1970-01-01
    相关资源
    最近更新 更多