Я нашел несколько странных ошибок HLSL — или Пикс говорит глупости:
У меня есть 2 ортогональных вектора: A = {0.0f, -1.0f, 0.0f} и B {0.0f, 0.0f, 1.0f}
Если я использую точечную функцию HLSL, вывод будет (-0.0f), что имеет смысл, НО теперь значение этого вывода равно -0.0000675917 (это то, что говорит Пикс — и что выводит шейдер), а это не то, что я ожидал;
Даже если я сам вычислю точечный продукт (A.x * B.x + A.y * B.y + и т. Д.), Результат все равно 0.0f, но акос моего результата не равен нулю.
Мне нужно, чтобы результат acos был как можно точнее, потому что я хочу раскрасить свои вершины в соответствии с углом между нормалью треугольника и данным вектором.
float4 PS_MyPS(VS_OUTPUT input) : COLOR
{
float Light = saturate(dot(input.Normal, g_LightDir)) + saturate(dot(-input.Normal, g_LightDir)); // compute the lighting
if (dot(input.Vector, CameraDirection) < 0) // if the angle between the normal and the camera direction is greater than 90 degrees
{
input.Vector = -input.Vector; // use a mirrored normal
}
float angle = acos(0.0f) - acos(dot(input.Vector, Vector));
float4 Color;
if (angle > Angles.x) // Set the color according to the Angle
{
Color = Color1;
}
else if (angle > Angles.y)
{
Color = Color2;
}
else if (angle >= -abs(Angles.y))
{
Color = Color3;
}
else if (angle >= Angles.z)
{
Color = Color4;
}
else
{
Color = Color5;
}
return Light * Color;
}
Он отлично работает для углов выше 0,01 градуса, но дает неправильные результаты для меньших значений.
Другие найденные мной ошибки: -функция length в hlsl возвращает 1 для вектора (0, -0, -0, 0) в Pix, а функция HLSL «any» в этом векторе также возвращает true. Это будет означать, что -0.0f! = 0.0f.
Кто-нибудь еще сталкивался с этим и, возможно, есть обходной путь для моей проблемы?
Я протестировал его на Intel HD Graphics 4600 и карте Nvidia с теми же результатами.
Одна из основных причин, почему acos может возвращать плохие результаты, заключается в том, что всегда помните, что acos принимает значения от -1,0 до 1,0.
Следовательно, если значение даже немного превышает (1,00001 вместо 1,0), оно может вернуть неверный результат.
Я имею дело с этой проблемой путем принудительного ограничения, т.е. ставя чек на
if(something>1.0)
something = 1.0;
else if(something<-1.0)
something = -1.0;
Других решений пока нет …