【问题标题】:Weird behavior of GLSL code (variables, conditional operator)GLSL 代码的奇怪行为(变量、条件运算符)
【发布时间】:2021-09-16 13:57:24
【问题描述】:

我正在尝试使用简单的片段着色器将 360° 纹理实现到 OpenGL 3D 项目中,在其中我从相机的位置向每个像素的方向发送一个单位向量,并通过使用一些三角函数我得到像素的纹理坐标。起初,一切正常,但在一个方向(负 x)有一些像素颜色错误(它们具有纹理底部的颜色,它们通常不应该具有)。在尝试调试时,我发现:

有了这段代码,像素问题就出现了:

vec2 textureCoords = vec2(
        ((unitV.x < 0.0 ? 0.0 : 0.5) + (atan(unitV.z / unitV.x) / TOWPI)),
        (0.5 - (asin(unitV.y) / PI))
out_Color = texture(skyTexture, textureCoords);

但是使用这段代码它工作得很好:

  if(unitV.x < 0.0)
        out_Color = texture(skyTexture, vec2(0.0 + (atan(unitV.z / unitV.x) / TOWPI), (0.5 - (asin(unitV.y) / PI))));
  else
        out_Color = texture(skyTexture, vec2(0.5 + (atan(unitV.z / unitV.x) / TOWPI), (0.5 - (asin(unitV.y) / PI))));

(vec3 unitV; 是像素从相机位置的归一化方向向量,它是针对每个像素作为局部变量从制服中计算出来的。)

如果我没有忽略一些非常基本的东西,这两个版本应该是完全一样的,但是结果是不同的......

注意:我的主要问题不是像素有时是错误的,而只是这两个,在我看来,确切的代码位会始终导致不同的结果。

【问题讨论】:

  • 什么是unitV?制服?属性?它有哪个范围?我问是因为第二个版本要求unitV.x 是动态统一的。

标签: opengl glsl conditional-operator


【解决方案1】:

如果我没有忽略一些非常基本的东西,这两个版本应该是完全相同的,但结果是不同的..

不,它们不一定会产生相同的结果。如果uintV 是动态统一的,它们只会产生相同的结果。

当你对纹理进行采样时,GL 会计算纹理坐标梯度以确定纹理是缩小还是放大,当使用 mip-mapping 时,还会计算要使用的细节级别。

通常,GPU 将通过与 2x2 像素块中相邻像素的值进行有限差分来近似求导数。因此,如果您碰巧有一个 2x2 像素块,例如左侧像素为uintV.x &lt; 0,右侧像素为uintV.x &gt;= 0,则 tex-coords 将出现 0.5 的巨大跳跃,这意味着 GL 将假设纹理的一半映射到单个像素,需要非常高的 mipmap 级别。

当你写作时:

if(unitV.x < 0.0)
        out_Color = texture(skyTexture, vec2(0.0 + (atan(unitV.z / unitV.x) / TOWPI), (0.5 - (asin(unitV.y) / PI))));
  else
        out_Color = texture(skyTexture, vec2(0.5 + (atan(unitV.z / unitV.x) / TOWPI), (0.5 - (asin(unitV.y) / PI))));

如果uintV 不是动态统一的,纹理采样的效果仍然未定义,正如评论中提到的@BDL。这里的问题是,如果您在同一个调用组中有两个调用采用不同的分支,它们将对从未计算过的值进行有限差分,因为相邻像素甚至没有执行该分支。它可能会给你一些“更好”的结果,但只是偶然。

正确使用隐式渐变的正确方法是:

vec4 out_ColorA = texture(skyTexture, vec2(0.0 + ...));    
vec4 out_ColorB = texture(skyTexture, vec2(0.5 + ...));
out_Color = (unitV.x < 0.0) ? outCOlorA : out_ColorB;

但是,在您的用例中,使用 explicit 渐变可能会更好:

vec2 texcoords = vec2((atan(unitV.z / unitV.x) / TOWPI), (0.5 - (asin(unitV.y) / PI)));
vec2 gradX = dFdx(texcoords);
vec2 gradY = dFdy(texcoords);
out_Color = textureGrad(skyTexture, vec2(((unitV.x<0.0)?0.0:0.5)+texcoords.x,texcoords.y), gradX, gradY);

【讨论】:

    猜你喜欢
    • 2015-02-01
    • 2010-12-16
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 2013-03-13
    • 2019-11-17
    • 2011-10-21
    • 1970-01-01
    相关资源
    最近更新 更多