Sus*_*lik 6 c++ opengl artifacts glsl
当GLSL着色器在以下GPU上生成错误图像时遇到问题:
GT 430
GT 770
GTX 570
GTX 760
但正常工作:
Intel HD Graphics 2500
Intel HD 4000
Intel 4400
GTX 740M
Radeon HD 6310M
Radeon HD 8850
着色器代码如下:
bool PointProjectionInsideTriangle(vec3 p1, vec3 p2, vec3 p3, vec3 point)
{
vec3 n = cross((p2 - p1), (p3 - p1));
vec3 n1 = cross((p2 - p1), n);
vec3 n2 = cross((p3 - p2), n);
vec3 n3 = cross((p1 - p3), n);
float proj1 = dot((point - p2), n1);
float proj2 = dot((point - p3), n2);
float proj3 = dot((point - p1), n3);
if(proj1 > 0.0)
return false;
if(proj2 > 0.0)
return false;
if(proj3 > 0.0)
return false;
return true;
}
struct Intersection
{
vec3 point;
vec3 norm;
bool valid;
};
Intersection GetRayTriangleIntersection(vec3 rayPoint, vec3 rayDir, vec3 p1, vec3 p2, vec3 p3)
{
vec3 norm = normalize(cross(p1 - p2, p1 - p3));
Intersection res;
res.norm = norm;
res.point = vec3(rayPoint.xy, 0.0);
res.valid = PointProjectionInsideTriangle(p1, p2, p3, res.point);
return res;
}
struct ColoredIntersection
{
Intersection geomInt;
vec4 color;
};
#define raysCount 15
void main(void)
{
vec2 radius = (gl_FragCoord.xy / vec2(800.0, 600.0)) - vec2(0.5, 0.5);
ColoredIntersection ints[raysCount];
vec3 randomPoints[raysCount];
int i, j;
for(int i = 0; i < raysCount; i++)
{
float theta = 0.5 * float(i);
float phi = 3.1415 / 2.0;
float r = 1.0;
randomPoints[i] = vec3(r * sin(phi) * cos(theta), r * sin(phi)*sin(theta), r * cos(phi));
vec3 tangent = normalize(cross(vec3(0.0, 0.0, 1.0), randomPoints[i]));
vec3 trianglePoint1 = randomPoints[i] * 2.0 + tangent * 0.2;
vec3 trianglePoint2 = randomPoints[i] * 2.0 - tangent * 0.2;
ints[i].geomInt = GetRayTriangleIntersection(vec3(radius, -10.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, 0.0), trianglePoint1, trianglePoint2);
if(ints[i].geomInt.valid)
{
float c = length(ints[i].geomInt.point);
ints[i].color = vec4(c, c, c, 1.0);
}
}
for(i = 0; i < raysCount; i++)
{
for(j = i + 1; j < raysCount; j++)
{
if(ints[i].geomInt.point.z < ints[i].geomInt.point.z - 10.0)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
ColoredIntersection tmp = ints[j];
ints[j] = ints[i];
ints[i] = tmp;
}
}
}
vec4 resultColor = vec4(0.0, 0.0, 0.0, 0.0);
for(i = 0; i < raysCount + 0; i++)
{
if(ints[i].geomInt.valid)
resultColor += ints[i].color;
}
gl_FragColor = clamp(resultColor, 0.0, 1.0);
}
Run Code Online (Sandbox Code Playgroud)
Upd:我用内置函数替换了向量规范化,并添加了gl_FragColor claming以防万一.
代码是实际着色器的简化版本,预期图像是:

但我得到的是:
代码的随机旋转完全消除了伪像.例如,如果我改变线
if(ints[i].geomInt.valid) //1
Run Code Online (Sandbox Code Playgroud)
至
if(ints[i].geomInt.valid == true) //1
Run Code Online (Sandbox Code Playgroud)
显然不应该以任何方式影响逻辑或完全消除不做任何事情(标记为2)的双重循环消失.请注意,双重循环完全没有任何条件
if(ints[i].geomInt.point.z < ints[i].geomInt.point.z - 10.0)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
return;
ColoredIntersection tmp = ints[j];
ints[j] = ints[i];
ints[i] = tmp;
}
Run Code Online (Sandbox Code Playgroud)
永远不会满足(左右两侧有索引i,而不是i,j)并且没有NaN.这段代码绝对没有任何东西以某种方式产生工件.
您可以使用此项目自行测试着色器和演示(完整的MSVS 2010项目+源代码+已编译的二进制文件和着色器,使用包含的SFML):https://dl.dropboxusercontent.com/u/25635148/ShaderTest.zip
我在这个测试项目中使用sfml,但这是100%不相关的,因为我遇到这个问题的实际项目不使用这个lib.
我想知道的是为什么这些工件出现以及如何可靠地避免它们.
如果有人仍然感兴趣,我在许多专业网站上提出了这个问题,包括 opengl.org 和 devtalk.nvidia.com。我没有收到关于我的着色器问题的任何具体答案,只是收到一些如何解决我的问题的建议。就像使用 if(condition == true) 而不是 if(condition) 一样,使用尽可能简单的算法等。最后,我选择了最简单的代码轮换之一来消除问题:我刚刚替换
struct Intersection
{
vec3 point;
vec3 norm;
bool valid;
};
Run Code Online (Sandbox Code Playgroud)
和
struct Intersection
{
bool valid;
vec3 point;
vec3 norm;
};
Run Code Online (Sandbox Code Playgroud)
还有许多其他代码轮换使工件消失,但我选择了这个,因为我能够在我之前遇到问题的大多数其他系统上进行测试。