0

I found a few strange HLSL bugs - or Pix is telling nonsense:

I have 2 orthogonal Vectors: A = { 0.0f, -1.0f, 0.0f } and B { 0.0f, 0.0f, 1.0f }

If I use the HLSL dot function, the output is (-0.0f) which makes sense BUT now the acos of that output is -0.0000675917 (that's what Pix says - and what the shader outputs) which is not what I had expected;

Even if I compute the dotproduct myself (A.x*B.x + A.y * B.y + etc.) the result is still 0.0f but the acos of my result isn't zero.

I do need the result of acos to be as precisely as possible because i want to color my vertices according to the angle between the triangle normal and a given vector.

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;
}

It works fine for angles above 0.01 degrees, but gives wrong results for smaller values.

The other bugs I found are: The "length"-function in hlsl returns 1 for the vector (0, -0, -0, 0) in Pix and the HLSL function "any" on that vector returns true as well. This would mean that -0.0f != 0.0f.

Has anyone else encountered these and maybe has a workaround for my problem? I tested it on an Intel HD Graphics 4600 and a Nvidia card with the same results.

Tomas Dittmann
  • 424
  • 7
  • 18
  • Provide a [short, self-contained, correct example](http://sscce.org). – Oswald Oct 24 '13 at 15:28
  • If you use the HLSL dot function on A = { 0.0f, -1.0f, 0.0f } and B { 0.0f, 0.0f, 1.0f } and the output is -0.0f (which makes sense according to your question), why do you attribute the bug to HLSL instead of to the `acos` function? – Oswald Oct 24 '13 at 15:31
  • What do you mean by *seems to have the lenght 1*? How did you test it? – Oswald Oct 24 '13 at 15:34
  • To answer all your questions: 1. I will provide the example tomorrow, 2. the acos function is used within a hlsl shader and 3. I opened my project in Pix and debugged the shader. There the length function returned 1 for the (0,-0,-0,0) vector. – Tomas Dittmann Oct 24 '13 at 16:52
  • ok I get get some funny results with length also (seems the bug is in the compiler actually). using fxc I got some really odd stuff. About acos, acos(0) is not 0, but PI/2 , acos(1) = 0. On another note, your angle calculation can just use the dot product, you don't need acos there. Last one for the road, can I see how you declare your variables in your shader (might be a cbuffer issue), and your VS_OUTPUT definition? – mrvux Oct 26 '13 at 21:58

1 Answers1

0

One of the primary reasons why acos may return bad results is because always remember that acos takes values between -1.0 and 1.0.

Hence if the value exceeds even slightly(1.00001 instead of 1.0) , it may return incorrect result.

I deal with this problem by forced capping i.e putting in a check for

if(something>1.0)
   something = 1.0;
else if(something<-1.0)
   something = -1.0;
rajaditya_m
  • 289
  • 1
  • 4
  • 14