hlsl неожиданный результат acos

Я нашел несколько странных ошибок HLSL — или Pix говорит ерунду:

У меня есть 2 ортогональных вектора: A = {0.0f, -1.0f, 0.0f} и B {0.0f, 0.0f, 1.0f}

Если я использую точечную функцию HLSL, вывод будет (-0,0f), что имеет смысл, НО теперь acos этого вывода равен -0,0000675917 (это то, что говорит Pix - и то, что выводит шейдер), что не то, что я ожидал;

Даже если я сам вычисляю скалярное произведение (A.x*B.x + A.y * B.y + и т. д.), результат все равно будет 0,0f, но значение acos моего результата не равно нулю.

Мне нужно, чтобы результат 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 градуса, но дает неправильные результаты для меньших значений.

Другие ошибки, которые я обнаружил: функция «длина» в hlsl возвращает 1 для вектора (0, -0, -0, 0) в Pix, а функция HLSL «любой» для этого вектора также возвращает true. Это будет означать, что -0.0f != 0.0f.

Кто-нибудь еще сталкивался с этим и, возможно, у меня есть обходной путь для моей проблемы? Я протестировал его на Intel HD Graphics 4600 и карте Nvidia с теми же результатами.


person Tomas Dittmann    schedule 24.10.2013    source источник
comment
Предоставьте краткий, самостоятельный, правильный пример.   -  person Oswald    schedule 24.10.2013
comment
Если вы используете точечную функцию HLSL для A = {0.0f, -1.0f, 0.0f} и B {0.0f, 0.0f, 1.0f}, а результат равен -0.0f (что имеет смысл в соответствии с вашим вопросом), почему вы приписываете ошибку HLSL, а не функции acos?   -  person Oswald    schedule 24.10.2013
comment
Что вы подразумеваете под имеет длину 1? Как вы это тестировали?   -  person Oswald    schedule 24.10.2013
comment
Чтобы ответить на все ваши вопросы: 1. завтра я приведу пример, 2. функция acos используется в шейдере hlsl и 3. я открыл свой проект в Pix и отладил шейдер. Там функция длины вернула 1 для вектора (0,-0,-0,0).   -  person Tomas Dittmann    schedule 24.10.2013
comment
Хорошо, я также получаю забавные результаты с длиной (кажется, на самом деле ошибка в компиляторе). используя fxc, я получил действительно странные вещи. Что касается acos, acos(0) не равно 0, а PI/2 , acos(1) = 0. С другой стороны, ваш расчет угла может просто использовать скалярное произведение, вам не нужен acos. Последнее на дороге, могу я увидеть, как вы объявляете свои переменные в своем шейдере (может быть, проблема с cbuffer) и ваше определение VS_OUTPUT?   -  person mrvux    schedule 27.10.2013


Ответы (1)


Одна из основных причин, по которой 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;
person rajaditya_m    schedule 24.10.2013
comment
В вопросе ввод acos() близок к 0 (это точечный продукт двух ортогональных векторов). - person Oswald; 24.10.2013
comment
Он должен быть точно равен 0, который находится между 1,0 и -1,0. - person Tomas Dittmann; 24.10.2013