Я столкнулся с проблемой, когда шейдер GLSL генерирует неправильное изображение на следующих графических процессорах:
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);
}
Upd: Я заменил векторную нормализацию встроенными функциями и на всякий случай добавил claming gl_FragColor.
Код представляет собой упрощенную версию реального шейдера, ожидаемое изображение:
Но я получаю следующее:
Случайные повороты кода полностью удаляют артефакты. Например, если я изменю строку
if(ints[i].geomInt.valid) //1
to
if(ints[i].geomInt.valid == true) //1
который, по-видимому, не должен каким-либо образом влиять на логику или полностью удалять двойной цикл, который ничего не делает (отмечен как 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;
}
Никогда не может быть удовлетворено (левая и правая стороны имеют индекс i, а не i, j) и нет NaN. Этот код абсолютно ничего не делает, но каким-то образом производит артефакты.
Вы можете протестировать шейдер и демонстрацию самостоятельно, используя этот проект (полный проект MSVS 2010 + исходники + скомпилированный двоичный файл и шейдер, использует включенный SFML): https://dl.dropboxusercontent.com/u/25635148/ShaderTest.zip
Я использую sfml в этом тестовом проекте, но это на 100% нерелевантно, потому что реальный проект, о котором я упоминал об этой проблеме, не использует эту библиотеку.
Я хочу знать, почему появляются эти артефакты и как их надежно избежать.
return
из своей ветки, это что-нибудь изменит? - person Andon M. Coleman   schedule 27.04.2014#pragma optionNV
. - person Andon M. Coleman   schedule 27.04.2014lowp
, например, гарантирует не меньше 2 ^ -8. - person Andon M. Coleman   schedule 28.04.2014