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!