我正在编写一个简单的着色器并遇到一个奇怪的问题。
我基本上是使用sampler2D数组渲染一堆纹理,我从中选择所需的纹理。
#version 330 core
layout (location = 0) out vec4 color;
in DATA
{
vec4 position;
vec4 color;
vec2 texCoord;
flat int texID;
} fs_in;
uniform sampler2D textures[16];
void main()
{
vec4 texColor = fs_in.color;
if (fs_in.texID > 0)
{
texColor = fs_in.color * texture(textures[fs_in.texID - 1], fs_in.texCoord);
}
color = texColor;
}
然而,这段代码在纹理上给了我奇怪的文物: image
更换
texColor = fs_in.color * texture(textures[fs_in.texID - 1], fs_in.texCoord);
以下
for (int i = 0; i < 16; i++)
if (fs_in.texID - 1 == i)
texColor = fs_in.color * texture(textures[i], fs_in.texCoord);
解决了问题:image
此外,此问题仅出现在使用OpenGL的基于AMD的计算机上4.5.13469兼容性配置文件上下文21.19.525.258
在Surface Pro上运行原始程序非常合适。
也许我错过了一些明显的东西,但我不知道为什么会出现这个问题,或者为什么更改会修复它。解释赞赏。
〜石头
答案 0 :(得分:3)
#version 330 core
在GLSL 3.30中,constant expressions只能访问 的采样器数组。你的着色器不应该编译。
但是,让我们假装您的硬件比GLSL 3.30支持更多。在这种情况下:
textures[fs_in.texID - 1]
在GLSL 4.00+中,dynamically uniform expressions只能访问 的采样器数组。除非您只渲染一个三角形,或者每个三角形都具有相同的fs_in.texID
值,否则该表达式不动态均匀。而且我猜不是,因为你没有使用uniform
。
如果使用不是动态统一的表达式索引不透明类型的数组,则会得到未定义的行为。
以下
for (int i = 0; i < 16; i++) if (fs_in.texID - 1 == i) texColor = fs_in.color * texture(textures[i], fs_in.texCoord);
即使这会调用未定义的行为。虽然表达式i
本身可以是动态统一的,因为该语句只是有条件地执行,但该条件并不保证所使用的i
的值对于调用组中的所有调用都是相同的。
所以它仍然没有动态统一。它只是未定义的行为,恰好恰好工作。不保证它可以用于其他任何事情。
你无法逃避规则;您无法在渲染命令的中间切换要使用的纹理。如果这是你真正想要的,那么你不需要一系列纹理;你想要一个数组纹理:
uniform sampler2DArray textures;
void main()
{
vec4 texColor = fs_in.color;
if (fs_in.texID > 0)
{
texColor = fs_in.color * texture(textures, vec3(fs_in.texCoord, fs_in.texID - 1));
}
color = texColor;
}
或者,只需删除条件,使纹理的第0层仅包含1,并始终从纹理中获取(因为有条件地执行may require you to manually provide derivatives):
uniform sampler2DArray textures;
void main()
{
color = fs_in.color * texture(textures, vec3(fs_in.texCoord, fs_in.texID));
}