我尝试用一个简单的片段着色器在OpenGL 3D项目中实现一个360°纹理,我从摄像头的位置向每个像素的方向发送一个单位向量,然后使用一些三角函数得到像素的纹理坐标。但是在一个方向(负x)上有一些像素的颜色错误(它们的颜色来自纹理的底部,这是它们通常不应该有的)。
在这段代码中,像素问题就出现了:
vec2 textureCoords = vec2(
((unitV.x < 0.0 ? 0.0 : 0.5) + (atan(unitV.z / unitV.x) / TWOPI)),
(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) / TWOPI), (0.5 - (asin(unitV.y) / PI))));
else
out_Color = texture(skyTexture, vec2(0.5 + (atan(unitV.z / unitV.x) / TWOPI), (0.5 - (asin(unitV.y) / PI))));
(vec3 unitVi是来自摄像机位置的像素的归一化方向向量,它是作为来自均匀性的局部变量针对每个像素计算的。)
“如果我没有忽略一个非常基本的东西,这两个版本应该是完全一样的,但结果却不一样......”
注意:我的主要问题不是像素有时是错误的事实,它只是这两个事实,在我看来,确切的代码位导致不同的结果一致。
1条答案
按热度按时间wlzqhblo1#
如果我没有忽略一些非常基本的东西,这两个版本应该是完全相同的,但结果是不同的。
不,它们不一定会产生相同的结果,只有当
uintV
是动态一致的时,它们才会产生相同的结果。对纹理进行采样时,GL将计算纹理坐标梯度,以确定纹理是缩小还是放大,并且在使用mip贴图时,还将计算要使用的细节级别。
通常情况下,GPU会通过与2x2像素块中相邻像素的值进行有限差分来 * 近似 * 导数。因此,如果您碰巧有一个2x2像素块,其中,假设左侧像素为
uintV.x < 0
,右侧像素为uintV.x >= 0
,则纹理坐标将出现0.5的巨大跳跃。这意味着GL将假定一半纹理被Map到单个像素,这需要非常高的小中见大贴图级别。当你写:
如果
uintV
不是动态一致的,纹理采样的效果仍然是不确定的,正如@BDL在注解中提到的。这里的问题是,如果你在同一个调用组中有两个调用采用不同的分支,它们将对从未计算过的值进行有限差分,因为相邻像素甚至没有执行该分支。它可能会给予你一些“更好”的结果,但只是偶然。使用隐式渐变的正确方法是:
但是,在您的用例中,使用 * 显式 * 渐变可能会更好: