2

I am trying to make a 3D direction adjustment algorithm that enters a unit vector and returns the closest (angle-wise) vector whose angle on each axis is a multiple of a given angle.

For example, if the given angle is 45º, I would snap the angle to 8 steps in each axis for a total of 26 possibilities. I hope that was clear enough. If it's not please let me know.

This is my current attempt:

float3 SnapDirection(float3 input)
    {   
        float3 angle = math.acos(input);
        float3 rounded = math.round(angle / 45) * 45;
        float3 cosine = math.cos(rounded);
        return math.normalize(cosine);
    }

What I expect it top output is the option with the smallest angle to the input. I measure it by math.acos(math.dot(input, output)). It mostly correct results but there are a good amount of cases where it doesn't get the best option.

This is because I'm rounding each axis independently, and so I get wrong results in the cases where the angle to one or 2 of the axes are longer than the optimal solution but the overall angle is shorter.

Consider the following case:

  • Input => (0.3546994, 0.3626332, 0.861792)
  • Current output => (0, 0, 1)
  • Best output => (0.5773503, 0.5773503, 0.5773503)

Those vector correspond to the following angles:

  • Input angles => ~(69.2º, 68.7º, 30.5º)
  • Current output angles => (90º, 90º 45º)
  • Best output angles => (45º, 45º, 45º)

And below you can see that the algorithm thinks the current result is the best because each number is smaller:

  • Difference input-current => (20.8º, 21.3º, 14.5º)
  • Difference input-best => (24.2º, 23.7º, 14.5º)

But the angle ends up being bigger:

  • Actual angle from input to current => 30.5º
  • Actual angle from input to best => 24.5º

Additionally, I need this code to be as performant as possible and avoid branching as I may need to port this to GPU later on.

Thank you very much!

JoNax97
  • 21
  • 4
  • What answer do you want for the 1st test case? 68 - 45 = 23 while 45 - 32 = 13. So is the correction 23, 13 or something else? – jdweng Jun 08 '20 at 11:14
  • I'ld guess the issue lies in rounding [to even by default](https://stackoverflow.com/questions/977796/why-does-math-round2-5-return-2-instead-of-3) meaning if your values is e.g. `0.5` it would be rounded to `0` not to `1`. [`Math.Round`](https://learn.microsoft.com/dotnet/api/system.math.round) has an overload taking a [`MidpointRounding`](https://learn.microsoft.com/dotnet/api/system.midpointrounding) to further specify this behaviour. Your code looks like shader code so I don't know if you can pass it in there as well – derHugo Jun 08 '20 at 12:20
  • @jdweng I've edited my example, hopefully it's clearer. I want the direction with the smallest angle to the input. – JoNax97 Jun 08 '20 at 13:12
  • @derHugo I'm using a shader-like library that is specific to unity. The rounding is actually right; my problem is conceptual: I'm rounding axis-wise but i need something that takes into account a shorter angle even when some axis may be longer. – JoNax97 Jun 08 '20 at 13:15

0 Answers0