🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Get rotation angle from normalized 2D vector

Started by
49 comments, last by JoeJ 6 years ago

Hi, is it possible to compute the rotation angle from a normalized 2D vector without having to use the atan2f function ?

thanks

S T O P C R I M E !

Visual Pro 2005 C++ DX9 Cubase VST 3.70 Working on : LevelContainer class & LevelEditor

Advertisement

Well, the geometric solution is to use the arctangent trigonometric function. However, by itself arctangent will give you the angle within the range -90 to 90 degrees, rather than 0 to 360, so to determine the angle within 360 degrees you can construct a function with 4 different cases, 1 for each of the quadrants (plus a fifth branch for the degenerate case of x==y==0), and use the sign of the x and y components to determine which quadrant the result lies within, correcting the result based on the quadrant to return a value within the range 0 to 360. At which point, congratulations. You just implemented atan2.

Why do you need to avoid using atan2?

Alternatively, you could use acos:

float angle = acos(unitV.x);

if (unitV.y < 0) angle = -angle;

 

The difference is atan2 also works if the vector is not unit length, so probably acos is faster but i don't know.

Hi, thanks for the reply`s.

 

17 hours ago, JTippetts said:

Why do you need to avoid using atan2?

I am making a worm move with inverse kinetics, i like to avoid all heavey math functions, so i need a smart function that gives about the same results.

 

17 hours ago, JTippetts said:

However, by itself arctangent will give you the angle within the range -90 to 90 degrees, rather than 0 to 360

That is not true, it can give values higher then Pi, and goes not below -Pi.

The angle is not the problem, the problem is the rendering, it needs to be rendered at the right angle, for the rest it does nothing.

 

15 hours ago, JoeJ said:

Alternatively, you could use acos:

float angle = acos(unitV.x);

if (unitV.y < 0) angle = -angle;

 

The difference is atan2 also works if the vector is not unit length, so probably acos is faster but i don't know.

It still uses a heavey math function, thanks but no thanks.

I need something fast.

 

By the way : i am using this function for the inverse kinematics :

float Q_rsqrt( float number ){	union {		float f;		uint32_t i;	} conv;		float x2;	const float threehalfs = 1.5F;	x2 = number * 0.5F;	conv.f  = number;	conv.i  =  0x5F375A86 - ( conv.i >> 1 );	conv.f  = conv.f * ( threehalfs - ( x2 * conv.f * conv.f ) );	return conv.f;}
	

 

https://en.wikipedia.org/wiki/Fast_inverse_square_root

S T O P C R I M E !

Visual Pro 2005 C++ DX9 Cubase VST 3.70 Working on : LevelContainer class & LevelEditor

4 minutes ago, the incredible smoker said:

I need something fast.

It's probably a waste of time.

E.g. first i found is this: (https://stackoverflow.com/questions/3380628/fast-arc-cos-algorithm)

Quote

A simple cubic approximation, the Lagrange polynomial for x ∈ {-1, -½, 0, ½, 1}, is:

double acos(x) {
   return (-0.69813170079773212 * x * x - 0.87266462599716477) * x + 1.5707963267948966;
}

It has a maximum error of about 0.18 rad.

The problem is, 0.18 rad i s a lot. To improve this, you need more constants and more math, and likely you still and up with unacceptable edge cases.

So, like anyone would say, be sure the trig functions really are a performance problem, before you start to mess with those approximizations.

(I may change my mind if you tell me the difference from using Q_rsqrt you get by profiling. :) )

Some points:

  1. 'Fast' inverse square root is no longer very useful, since SSE and SIMD was invented, it will do this in hardware faster and more accurately.
  2. Atan2 is also done in hardware I believe, and it can be calculated with SIMD, there is an intel intrinsic for it (mm_atan2_ps) so if you google that .. it probably uses a couple of standard SIMD calls I'm sure you can do it on non-intel compiler. It will probably be faster and more accurate than anything you can roll, or a lookup table.
  3. Have you profiled this? How do you normalize your vector for instance? How do you draw this? How many atan2 are you doing per frame? Are you sure this is a bottleneck?

Here is a SIMD implementation out of interest, the author claims 7.3x speedup over standard atan2 (more than a couple of instructions though lol):

https://github.com/divideconcept/FastTrigo/blob/master/fasttrigo.h

The thing is once i have this i can remove all sin, cos, atan2 in my game, it is used in all the enemy classes.

Lets say for every enemy at least 1 time al three sin cos & atan2 plus the worm that has 64 body parts, its 64 times atan2f per worm per frame if you want the rotation right per bodypart.

Now i have only the head aiming to the enemy with atan2f, then get the sin & cos for the direction of that rotation, here i also can use the fast inv sqrt instead of the sinus and cosinus,

Then all circle shaped bodyparts use invsqrt to place in position without rotation.

Finally the tail piece aims to the last bodypart with atan2 only to get the rendering right.

When i have some error it would not matters much since its for rendering only.

 

Suppose i have nice bodyparts that need rotation i would have to call 64 times per frame atan2, times many worms..

 

58 minutes ago, lawnjelly said:

Some points:

  1. 'Fast' inverse square root is no longer very useful, since SSE and SIMD was invented, it will do this in hardware faster and more accurately.
  2. Atan2 is also done in hardware I believe, and it can be calculated with SIMD, there is an intel intrinsic for it (mm_atan2_ps) so if you google that .. it probably uses a couple of standard SIMD calls I'm sure you can do it on non-intel compiler. It will probably be faster and more accurate than anything you can roll, or a lookup table.
  3. Have you profiled this? How do you normalize your vector for instance? How do you draw this? How many atan2 are you doing per frame? Are you sure this is a bottleneck?

I would need to activate a timer before calling the function, then display the value on screen.

I work on windows XP with a 32 bit machine, i like to make my game playable on older machines also.

Since when is SSE and SIMD ?,

i remember when programming synthesizers there is a significant  performance loss when using sin cos atan2 or whatever math function,

those computers had also has SSE back then 10 years ago or not ?

 

By the way for inverse square root i would still have to divide also : 1.0f / sqrtf( x );

I can not believe that will be faster then the fast invsqrt code i use now,

+ if i look online i see a graph with performance per math functions, would they lie ?

FLOPchart1.png

http://www.latkin.org/blog/2014/11/09/a-simple-benchmark-of-various-math-operations/

S T O P C R I M E !

Visual Pro 2005 C++ DX9 Cubase VST 3.70 Working on : LevelContainer class & LevelEditor

12 minutes ago, the incredible smoker said:

those computers had also has SSE back then 10 years ago or not ?

SSE2 for instance was introduced in 2000, wikipedia tells me. Windows 7 now no longer supports CPUs without SSE2. You'd be hard pressed to find a PC still operational that doesn't have it.

13 minutes ago, the incredible smoker said:

i remember when programming synthesizers there is a significant  performance loss when using sin cos atan2 or whatever math function

You are right in the sense that certain instructions on the whole tend to be slower than others, but the landscape has totally changed. When I started on 6502 CPU you could count the cycles used by an instruction, it hasn't been that way for many years now as modern CPUs do all sorts of jiggery pokery, re-ordering instructions etc, no one knows how they really work. And the things that are the bottleneck have changed, often it is memory access rather than instructions.

So for optimization today the name of the game is 'profiling', which is a a way of running a performance timing build of your program, which logs how long it spent in each function, and even on which line within each function. Working without timing information and using guesswork you can be wildly out in your estimations of what is slowing down your program. However even profiling only tells a fraction of the story as in a game it is often bottlenecked by the GPU which will not show up in a CPU profile.

You can also use timers to time running your test functions millions of times, but you have to be very careful not to get false results because of things like memory caching, and the compiler optimizing out your code.

22 minutes ago, the incredible smoker said:

I can not believe that will be faster then the fast invsqrt code i use now,

What can I say, hardware has moved on! :)

25 minutes ago, the incredible smoker said:

Lets say for every enemy at least 1 time al three sin cos & atan2 plus the worm that has 64 body parts, its 64 times atan2f per worm per frame if you want the rotation right per bodypart.

Now i have only the head aiming to the enemy with atan2f, then get the sin & cos for the direction of that rotation, here i also can use the fast inv sqrt instead of the sinus and cosinus,

This sounds like you use trig functions although there is no need for it?

E.g. to make the head pont towards goal, you could simple write:

vec2 diff = goal - head;

transform.xAxis = diff.Unit();

transform.yAxis = vec2(-transform.xAxis.y, transform.xAxis.x);

transform.pos = head;

The transform then renders the head pointing towards goal, and no trig required?

This topic is closed to new replies.

Advertisement