Get rotation angle from normalized 2D vector

Started by
49 comments, last by JoeJ 5 years, 9 months ago
Quote

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

False. The range of arctangent is -pi/2 to + pi/2 in radians (-90 to +90 in degrees).

Quote

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

I need something fast.

No, what you need is something that works. Only after you've benchmarked and determined that atan2 is too much of a performance loss (spoiler: it probably isn't) do you then need "something fast" (whatever that turns out to be). 

It seems like you've used your own superior intellect to reason your way into the position that "trigonometry is too slow", and you have to come up with a magical way of doing trigonometry faster than trigonometry.

If you have a 2D normalized vector, you have a triangle. Sorry, guy, but you're gonna need to do trigonometry in some fashion in order to obtain the angle. That's what trigonometry is. If the profiling indicates it's too much of a bottlneck, restructure and use SIMD as indicated before. But if you're looking for some magically fast way of doing trig that's faster than actually doing trig, you're barking up the wrong tree.

And, of course, as JoeJ has indicated, it's likely that you don't actually need to calculate the angle of the 2D vector. If it's just for rendering, you can construct a rotation matrix without having to call atan2. 

Advertisement

Really JoeJ ?, great, now let me find out how it works.

 

vec2 diff = goal - head; // understandable

 

transform.xAxis = diff unit(); ?, what is unit ?, and is the transform a D3DXMATRIXA16 ?

Would that be : D3DXMatrixRotationZ ?

D3DXMATRIX* D3DXMatrixRotationZ(
  _Inout_ D3DXMATRIX *pOut,
  _In_    FLOAT      Angle
);

Why would i need another rotation then ?, i,m making a 2D game.

And how can you pass a vector instead of float ?

 

S T O P C R I M E !

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

D3DXMatrixRotationZ is a utility function that lets you create a rotation matrix if you DO have the angle. In no way does it imply that you NEED the angle to build a rotation matrix. If you have a vector, calculating the angle then using that to build a matrix is taking the long way around.

To bad i have no expert knowledge about those matrices.

I only see a bunch of numbers, what would be the directx9 version to build a rotation matrix without a rotation angle ?

30 minutes ago, JTippetts said:

False. The range of arctangent is -pi/2 to + pi/2 in radians (-90 to +90 in degrees).

I am 100% sure, have you ever build a SlideRotation function that rotates the enemy towards the player ?, i guess not.

btw : i use -atan2f lolz i forgot, sorry.

 

30 minutes ago, JTippetts said:

And, of course, as JoeJ has indicated, it's likely that you don't actually need to calculate the angle of the 2D vector. If it's just for rendering, you can construct a rotation matrix without having to call atan2. 

That is exacly what i need, now i need to figure out how Joes code exact works for DirectX 9.

 

30 minutes ago, JTippetts said:

If you have a 2D normalized vector, you have a triangle. Sorry, guy, but you're gonna need to do trigonometry in some fashion in order to obtain the angle. That's what trigonometry is. If the profiling indicates it's too much of a bottlneck, restructure and use SIMD as indicated before. But if you're looking for some magically fast way of doing trig that's faster than actually doing trig, you're barking up the wrong tree.

 

I am also programming microchips with displays, i like to make a hardware game in the future also.

S T O P C R I M E !

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

By the way what are trig functions ?

S T O P C R I M E !

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

44 minutes ago, the incredible smoker said:

Really JoeJ ?, great, now let me find out how it works.

To understand you only need to think of it geometrically i grant you, and this applies to almost anything related to transformation matrices.
It's NOT necessary to know about linear algebra at all.

I'll comment the code:



	
vec2 diff = goal - head; // direction from head to goal. (imagine the goal is left from the head)
	vec2 dir = diff / diff.Length(); // make the vector unit length, that's what i've meant with Unit() 
	vec2 orientationXaxis = dir; // now the xAxis points along the direction from head to goal (imagine as a red line pointing to the left)
vec2 orientationYaxis = vec2(-dir.y, dir.x); // by swapping and flipping a sign, we get a perpendicular direction. (imagine green line upwards)
	// those two now vectors now define orientation as an orthogonal frame
// notice there is no rotation involved, we just construct the final orientation in place
// we could see this as a 2x2 orientation matrix if we want. But D3D wants a 4x4 matrix, so lets convert to this:
	D3DXMATRIX matrix;
// first 3 rows contain the orthonormal orientation axis:
matrix (0,0) = orientationXaxis.x; matrix (0,1) = orientationXaxis.y; matrix (0,2) = 0; matrix (0,3) = 0; // set x axis
matrix (1,0) = orientationYaxis.x; matrix (1,1) = orientationYaxis.y; matrix (1,2) = 0; matrix (1,3) = 0; // set y axis 
matrix (2,0) = 0; matrix (2,1) = 0; matrix (2,2) = 1; matrix (2,3) = 0; // z axis remains just z axis, because we don't change it for the 2D case
// final row is position:
matrix (3,0) = head.x; matrix (3,1) = head.y; matrix (3,2) = 0; matrix (3,2) = 1; 
	// (!) i'm afraid you need to swap all row/column indices, if you stick to D3Ds (unpractical) default convention (Syntax may be also wrong, i have no experience with D3D)
	

So again, try to imagine how this works and ask if necessary.
Next we could work out a routine to rotate one direction to another by a given factor using linear approximisation still avoiding trig.

 

Can't edit post, so code formatted again:


vec2 diff = goal - head; // direction from head to goal. (imagine the goal is left from the head)

vec2 dir = diff / diff.Length(); // make the vector unit length, that's what i've meant with Unit() :)

vec2 orientationXaxis = dir; // now the xAxis points along the direction from head to goal (imagine as a red line pointing to the left)
vec2 orientationYaxis = vec2(-dir.y, dir.x); // by swapping and flipping a sign, we get a perpendicular direction. (imagine green line upwards)

// those two now vectors now define orientation as an orthogonal frame
// notice there is no rotation involved, we just construct the final orientation in place
// we could see this as a 2x2 orientation matrix if we want. But D3D wants a 4x4 matrix, so lets convert to this:

D3DXMATRIX matrix;
// first 3 rows contain the orthonormal orientation axis:
matrix (0,0) = orientationXaxis.x; matrix (0,1) = orientationXaxis.y; matrix (0,2) = 0; matrix (0,3) = 0; // set x axis
matrix (1,0) = orientationYaxis.x; matrix (1,1) = orientationYaxis.y; matrix (1,2) = 0; matrix (1,3) = 0; // set y axis 
matrix (2,0) = 0; matrix (2,1) = 0; matrix (2,2) = 1; matrix (2,3) = 0; // z axis remains just z axis, because we don't change it for the 2D case
// final row is position:
matrix (3,0) = head.x; matrix (3,1) = head.y; matrix (3,2) = 0; matrix (3,2) = 1; 

// (!) i'm afraid you need to swap all row/column indices, if you stick to D3Ds (unpractical) default convention (Syntax may be also wrong, i have no experience with D3D)

 

11 minutes ago, the incredible smoker said:

By the way what are trig functions ?

cos sin atan acos... (trigonometry)

Plot of atan (arctangent) function

Trig is an abbreviation of trigonometry. Sin, cos, tan, asin, acos, atan, etc... are trig functions.

A rotation can be represented as a 3x3 matrix. The identity (ie, no rotation) matrix looks like


1 0 0
0 1 0
0 0 1

The three rows in this representation indicate the axes of the rotational space. The top row (1,0,0) indicates the X axis, middle row indicates Y, and bottom row indicates Z. Think of these 3 rows as vectors that describe how a thing is oriented in space.

A 2D rotation, represented as a 3D rotation matrix, might look something like:


 x y 0
-y x 0
 0 0 1

Where the 2D vector is (x,y). The vector (x,y,0) represents the X axis of the rotational space, the perpendicular vector (-y, x,0) represents the Y axis of the rotational space, and the vector (0,0,1) represents the Z axis. Of course, most APIs will use a 4x4 matrix that  encapsulates rotation as well as translation, in which case the 3x3 rotational component occupies the top left region .


 x y 0 TX
-y x 0 TY
 0 0 1 0
 0 0 0 1

Where TX and TY are the translation to apply. If I remember correctly (long time since I played with d3d) they store their matrices row-major, meaning the matrix in memory would look like


x y 0 TX -y x 0 TY 0 0 1 0 0 0 0 1

but I could be wrong about that.

Thanks Joe, i will save these codes on my USB stick and take a look this evening what i can make with it.

S T O P C R I M E !

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

9 minutes ago, JTippetts said:

Thanks JTippetts, does the but I could be wrong about that also count here ?

I will look this evening at it, maybe i accidently have >= instead of > in my code, that would explain.

For the rest 100% sure, i use something like this :

aimrot = -atan2f( x - player.x , y - player.y );

if( aimrot > D3DX_PI )aimrot -= D3DX_PI * 2.0f;

 

I wil take a look very carefully, i really would like to remove the if, lets find out.

will report back tomorrow.

 

Gonna save your info also on the USB stick, lets see.

bye for now.

S T O P C R I M E !

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

atan2 returns values in the range -pi to pi, corresponding to -180 to +180 degrees. You can add pi to the result to get values in the range of 0 to 2pi.

This topic is closed to new replies.

Advertisement