Euler Angles to OpenGL direction vector? - math

I am currently working on block-breaking in a Minecraft clone. In order to do so, I want use the camera's Euler angles to determine the direction vector of the camera's ray.
I have 2 angles: pitch and yaw.
Pitch rotates along the X axis and is positive when the player looks down, and negative when the player looks up. It cannot be greater than 90 degrees (looking straight down) and cannot be smaller than -90 degrees (looking straight up)
Yaw rotates along the Y axis. It can be a negative number and a positive number, depending on how many times the player turned and in which direction. For example, the player spawns in (yaw = 0) and instantly spins counter-clockwise 360 degrees. In such a case, yaw = -360.
As stated in the question, I am using OpenGL, so when yaw = 0, the player is looking down the negative Z-axis.
How can I generate a direction vector (must be a unit-vector) using only the Euler angles with the restrictions described above?

From your description of Pitch and Yaw, I am assuming that you are using a left-hand reference (pitch=0 and yaw=0 gives a camera vector (0.0, 0.0, 1.0).
The Pitch parameter moves the camera vector in the YZ plane :
Y = cos(pitchInRadians)
Z = sin(pitchInRadians)
The Yaw parameter moves the camera vector in the XZ plane :
X = sin(yawInRadians)
Z = cos(yawInRadians)
Combining the two would give you your final camera vector :
Cv = (sin(yaw), cos(pitch), sin(pitch)*cos(yaw))
As you should have noted, the angles are in radians. Since your post mentions angles in degrees, you will have to convert your degree angles to radians first :
radians = (degrees * PI) /180

Related

Attempting solve rotation

Im working now with some mod for the game, exactly i need rotate my player to any object.
I have two vector3, its my pos and object pos.
As usually we can
Vector3 Dir = object - mypos to get direction and calculate yaw and pitch using atan2 function, write it to our player angle and we will done rotation.
Problem. I first time see pitch value between 180 (mouse up) and 360 (mouse down), yaw 0 - 360, roll 0 (doesn’t matter now). Its represents as Vector3 euler. Of course if im using atan2 way i getting incorrect values for this eluer vector cause i getting less small (Lower than 180) or negative values for pitch, yaw seems in range. How to calculate correct?
My calcs:
Vector3 DoorDir = DoorOrigin - PlayerOrigin;
DoorDir = NormalizeVec(DoorDir);
float yaw = Rad2Deg(atan2(DoorDir.x, DoorDir.z));//Game has XZY coords.
float pitch = Rad2Deg(-1.f * atan2(DoorDir.y, sqrtf(DoorDir.x * DoorDir.x + DoorDir.z * DoorDir.z)));
SetAngles(Vector2(yaw,pitch)//Sets angles (converted yaw and pitch back to DEG)

Signed Rotation between two normals in 3D

Given a plane(in my case a triangle) normal N_T and a reference Normal N_R, both have the length 1.
I calculated the rotation_normal
N = N_T x N_R
and now i need to calculate the angle around this rotation_normal, which i get with the following calculation:
angle = acos(<N_T, N_R>), with <x,y> is the dotproduct of x and y
This angle is in the interval of [0°, 180°] and is the smallest angle between both normals.
So my problem is that if i want to rotate my triangle in a manner that its normal is equal to the reference normal, i need to know in which direction (positive or negative) the calculated angle is.
Does anybody know how to get this direction or how to solve this problem in general?
you need to use atan2 (4-quadrant arc tangens)
create reference plane basis vectors u,v
must be perpendicular to each other and lie inside plane
preferably unit vectors (or else you need to account for its size)
so let N=N_T x N_R; ... reference plane normal where the rotation will take place
U=N_T;
V= N x U; ... x means cross product
make them unit U/=|U|; V/=|V|; if they are not already
compute plane coordinates of N_R
u=(N_R.U); ... . means dot product
v=(N_R.V);
compute angle
ang=atan2(v,u);
if you do not have atan2 then use ang=atanxy(u,v);
this will give you angle in range ang=<0,2*M_PI>
if you want signed angle instead then add
if (ang>M_PI) ang-=2.0*M_PI; ... M_PI is well known constant Pi=3.1415...
now if you want the opposite sign direction then just use -ang

x,y,z polar coordinates in a sphere

I am currently using the following math to get the x,y,z coordinates with an assumed Hypotenuse of 150 and my known yaw pitch and roll.
float zPos = (float)Math.tan(Math.toRadians(rmPitch-90))*150;
float xPos = (float)Math.cos(Math.toRadians(90-rmYaw))*150;
float yPos = (float)Math.cos(Math.toRadians(rmYaw))*150;
Assuming a viewer is standing at 0,0,0 and looking up at P. Q is 150 units away and i know the yaw and pitch of the view);
my math seems to work fine until i my pitch gets closer to straight up and down, at which point i realize that x and y need to take into account z in some manner.. please help
The easiest way to think about this is to think about a unit circle embedded in the plane containing P and the z axis. There, the vector Q is one side of the triangle, and PQ is the other. So, armed with that picture in your head:
First, z should be cos(pitch), not tan(pitch). Then, to correct x, y for the pitch, multiply them by sin(pitch).
Note that this is assuming you did intend for phi/pitch to be the angle between the z axis and the vector (and not the more standard angle between the x-y plane and the vector).
There is a problem with Euler angles (i.e. the Azimuth, Pitch, Roll system of coordindates) when pitch is plus/minus 90 degrees. That seems to be what you're referring to, and its known as Grimbal Lock. I recently asked and then answered a question about this on math.stackexchange.com, so perhaps this link will help.
Since phi is the angle between P and the z-axis, the z-coordinate should be rho*cos(phi). Similarly x is rho*sin(phi)cos(theta), y is rho*sin(phi)sin(theta)
dsharlet, using tan(pitch-90) seemed to be working how i expected... if i switch to cos i have to make it (pitch+180) but following your advise the following code seems to work.. i must be flipping and axis or something weird.. can you speak a bit to the difference between tan(pitch-90) and cos(pitch+180)
float zPos = (float)Math.cos(Math.toRadians(rmPitch+180))*radius;
float xPos = (float)Math.cos(Math.toRadians(90-rmYaw))*(float)Math.sin(Math.toRadians(rmPitch))*radius;
float yPos = (float)Math.cos(Math.toRadians(rmYaw))*(float)Math.sin(Math.toRadians(rmPitch))*radius;

Calculate rotations to look at a 3D point?

I need to calculate the 2 angles (yaw and pitch) for a 3D object to face an arbitrary 3D point. These rotations are known as "Euler" rotations simply because after the first rotation, (lets say Z, based on the picture below) the Y axis also rotates with the object.
This is the code I'm using but its not working fully. When on the ground plane (Y = 0) the object correctly rotates to face the point, but as soon as I move the point upwards in Y, the rotations don't look correct.
// x, y, z represent a fractional value between -[1] and [1]
// a "unit vector" of the point I need to rotate towards
yaw = Math.atan2( y, x )
pitch = Math.atan2( z, Math.sqrt( x * x + y * y ) )
Do you know how to calculate the 2 Euler angles given a point?
The picture below shows the way I rotate. These are the angles I need to calculate.
(The only difference is I'm rotating the object in the order X,Y,Z and not Z,Y,X)
This is my system.
coordinate system is x = to the right, y = downwards, z = further back
an object is by default at (0,0,1) which is facing backward
rotations are in the order X, Y, Z where rotation upon X is pitch, Y is yaw and Z is roll
Here are my working assumptions:
The coordinate system (x,y,z) is such that positive x is to the right, positive y is down, and z is the remaining direction. In particular, y=0 is the ground plane.
An object at (0,0,0) currently facing towards (0,0,1) is being turned to face towards (x,y,z).
In order to accomplish this, there will be a rotation about the x-axis followed by one around the y-axis. Finally, there is a rotation about the z-axis in order to have things upright.
(The terminology yaw, pitch, and roll can be confusing, so I'd like to avoid using it, but roughly speaking the correspondence is x=pitch, y=yaw, z=roll.)
Here is my attempt to solve your problem given this setup:
rotx = Math.atan2( y, z )
roty = Math.atan2( x * Math.cos(rotx), z )
rotz = Math.atan2( Math.cos(rotx), Math.sin(rotx) * Math.sin(roty) )
Hopefully this is correct up to signs. I think the easiest way to fix the signs is by trial and error. Indeed, you appear to have gotten the signs on rotx and roty correct -- including a subtle issue with regards to z -- so you only need to fix the sign on rotz.
I expect this to be nontrivial (possibly depending on which octant you're in), but please try a few possibilities before saying it's wrong. Good luck!
Here is the code that finally worked for me.
I noticed a "flip" effect that occurred when the object moved from any front quadrant (positive Z) to any back quadrant. In the front quadrants the front of the object would always face the point. In the back quadrants the back of the object always faces the point.
This code corrects the flip effect so the front of the object always faces the point. I encountered it through trial-and-error so I don't really know what's happening!
rotx = Math.atan2( y, z );
if (z >= 0) {
roty = -Math.atan2( x * Math.cos(rotx), z );
}else{
roty = Math.atan2( x * Math.cos(rotx), -z );
}
Rich Seller's answer shows you how to rotate a point from one 3-D coordinate system to another system, given a set of Euler angles describing the rotation between the two coordinate systems.
But it sounds like you're asking for something different:
You have: 3-D coordinates of a single point
You want: a set of Euler angles
If that's what you're asking for, you don't have enough information. To find the Euler angles,
you'd need coordinates of at least two points, in both coordinate systems, to determine the rotation from one coordinate system into the other.
You should also be aware that Euler angles can be ambiguous: Rich's answer assumes the
rotations are applied to Z, then X', then Z', but that's not standardized. If you have to interoperate with some other code using Euler angles, you need to make sure you're using the same convention.
You might want to consider using rotation matrices or quaternions instead of Euler angles.
This series of rotations will give you what you're asking for:
About X: 0
About Y: atan2(z, x)
About Z: atan2(y, sqrt(x*x + z*z))
I cannot tell you what these are in terms of "roll", "pitch" and "yaw" unless you first define how you are using these terms. You are not using them in the standard way.
EDIT:
All right, then try this:
About X: -atan2(y, z)
About Y: atan2(x, sqrt(y*y + z*z))
About Z: 0
Talking about the rotation of axes, I think step 3 should have been the rotation of X'-, Y''-, and Z'-axes about the Y''-axis.

Triangle mathematics for game development

I'm trying to make a triangle (isosceles triangle) to move around the screen and at the same time slightly rotate it when a user presses a directional key (like right or left).
I would like the nose (top point) of the triangle to lead the triangle at all times. (Like that old asteroids game).
My problem is with the maths behind this. At every X time interval, I want the triangle to move in "some direction", I need help finding this direction (x and y increments/decrements).
I can find the center point (Centroid) of the triangle, and I have the top most x an y points, so I have a line vector to work with, but not a clue as to "how" to work with it.
I think it has something to do with the old Sin and Cos methods and the amount (angle) that the triangle has been rotated, but I'm a bit rusty on that stuff.
Any help is greatly appreciated.
The arctangent (inverse tangent) of vy/vx, where vx and vy are the components of your (centroid->tip) vector, gives you the angle the vector is facing.
The classical arctangent gives you an angle normalized to -90° < r < +90° degrees, however, so you have to add or subtract 90 degrees from the result depending on the sign of the result and the sign of vx.
Luckily, your standard library should proive an atan2() function that takes vx and vy seperately as parameters, and returns you an angle between 0° and 360°, or -180° and +180° degrees. It will also deal with the special case where vx=0, which would result in a division by zero if you were not careful.
See http://www.arctangent.net/atan.html or just search for "arctangent".
Edit: I've used degrees in my post for clarity, but Java and many other languages/libraries work in radians where 180° = π.
You can also just add vx and vy to the triangle's points to make it move in the "forward" direction, but make sure that the vector is normalized (vx² + vy² = 1), else the speed will depend on your triangle's size.
#Mark:
I've tried writing a primer on vectors, coordinates, points and angles in this answer box twice, but changed my mind on both occasions because it would take too long and I'm sure there are many tutorials out there explaining stuff better than I ever can.
Your centroid and "tip" coordinates are not vectors; that is to say, there is nothing to be gained from thinking of them as vectors.
The vector you want, vForward = pTip - pCentroid, can be calculated by subtracting the coordinates of the "tip" corner from the centroid point. The atan2() of this vector, i.e. atan2(tipY-centY, tipX-centX), gives you the angle your triangle is "facing".
As for what it's relative to, it doesn't matter. Your library will probably use the convention that the increasing X axis (---> the right/east direction on presumably all the 2D graphs you've seen) is 0° or 0π. The increasing Y (top, north) direction will correspond to 90° or (1/2)π.
It seems to me that you need to store the rotation angle of the triangle and possibly it's current speed.
x' = x + speed * cos(angle)
y' = y + speed * sin(angle)
Note that angle is in radians, not degrees!
Radians = Degrees * RadiansInACircle / DegreesInACircle
RadiansInACircle = 2 * Pi
DegressInACircle = 360
For the locations of the vertices, each is located at a certain distance and angle from the center. Add the current rotation angle before doing this calculation. It's the same math as for figuring the movement.
Here's some more:
Vectors represent displacement. Displacement, translation, movement or whatever you want to call it, is meaningless without a starting point, that's why I referred to the "forward" vector above as "from the centroid," and that's why the "centroid vector," the vector with the x/y components of the centroid point doesn't make sense. Those components give you the displacement of the centroid point from the origin. In other words, pOrigin + vCentroid = pCentroid. If you start from the 0 point, then add a vector representing the centroid point's displacement, you get the centroid point.
Note that:
vector + vector = vector
(addition of two displacements gives you a third, different displacement)
point + vector = point
(moving/displacing a point gives you another point)
point + point = ???
(adding two points doesn't make sense; however:)
point - point = vector
(the difference of two points is the displacement between them)
Now, these displacements can be thought of in (at least) two different ways. The one you're already familiar with is the rectangular (x, y) system, where the two components of a vector represent the displacement in the x and y directions, respectively. However, you can also use polar coordinates, (r, Θ). Here, Θ represents the direction of the displacement (in angles relative to an arbitary zero angle) and r, the distance.
Take the (1, 1) vector, for example. It represents a movement one unit to the right and one unit upwards in the coordinate system we're all used to seeing. The polar equivalent of this vector would be (1.414, 45°); the same movement, but represented as a "displacement of 1.414 units in the 45°-angle direction. (Again, using a convenient polar coordinate system where the East direction is 0° and angles increase counter-clockwise.)
The relationship between polar and rectangular coordinates are:
Θ = atan2(y, x)
r = sqrt(x²+y²) (now do you see where the right triangle comes in?)
and conversely,
x = r * cos(Θ)
y = r * sin(Θ)
Now, since a line segment drawn from your triangle's centroid to the "tip" corner would represent the direction your triangle is "facing," if we were to obtain a vector parallel to that line (e.g. vForward = pTip - pCentroid), that vector's Θ-coordinate would correspond to the angle that your triangle is facing.
Take the (1, 1) vector again. If this was vForward, then that would have meant that your "tip" point's x and y coordinates were both 1 more than those of your centroid. Let's say the centroid is on (10, 10). That puts the "tip" corner over at (11, 11). (Remember, pTip = pCentroid + vForward by adding "+ pCentroid" to both sides of the previous equation.) Now in which direction is this triangle facing? 45°, right? That's the Θ-coordinate of our (1, 1) vector!
keep the centroid at the origin. use the vector from the centroid to the nose as the direction vector. http://en.wikipedia.org/wiki/Coordinate_rotation#Two_dimensions will rotate this vector. construct the other two points from this vector. translate the three points to where they are on the screen and draw.
double v; // velocity
double theta; // direction of travel (angle)
double dt; // time elapsed
// To compute increments
double dx = v*dt*cos(theta);
double dy = v*dt*sin(theta);
// To compute position of the top of the triangle
double size; // distance between centroid and top
double top_x = x + size*cos(theta);
double top_y = y + size*sin(theta);
I can see that I need to apply the common 2d rotation formulas to my triangle to get my result, Im just having a little bit of trouble with the relationships between the different components here.
aib, stated that:
The arctangent (inverse tangent) of
vy/vx, where vx and vy are the
components of your (centroid->tip)
vector, gives you the angle the vector
is facing.
Is vx and vy the x and y coords of the centriod or the tip? I think Im getting confused as to the terminology of a "vector" here. I was under the impression that a Vector was just a point in 2d (in this case) space that represented direction.
So in this case, how is the vector of the centroid->tip calculated? Is it just the centriod?
meyahoocomlorenpechtel stated:
It seems to me that you need to store
the rotation angle of the triangle and
possibly it's current speed.
What is the rotation angle relative to? The origin of the triangle, or the game window itself? Also, for future rotations, is the angle the angle from the last rotation or the original position of the triangle?
Thanks all for the help so far, I really appreciate it!
you will want the topmost vertex to be the centroid in order to achieve the desired effect.
First, I would start with the centroid rather than calculate it. You know the position of the centroid and the angle of rotation of the triangle, I would use this to calculate the locations of the verticies. (I apologize in advance for any syntax errors, I have just started to dabble in Java.)
//starting point
double tip_x = 10;
double tip_y = 10;
should be
double center_x = 10;
double center_y = 10;
//triangle details
int width = 6; //base
int height = 9;
should be an array of 3 angle, distance pairs.
angle = rotation_angle + vertex[1].angle;
dist = vertex[1].distance;
p1_x = center_x + math.cos(angle) * dist;
p1_y = center_y - math.sin(angle) * dist;
// and the same for the other two points
Note that I am subtracting the Y distance. You're being tripped up by the fact that screen space is inverted. In our minds Y increases as you go up--but screen coordinates don't work that way.
The math is a lot simpler if you track things as position and rotation angle rather than deriving the rotation angle.
Also, in your final piece of code you're modifying the location by the rotation angle. The result will be that your ship turns by the rotation angle every update cycle. I think the objective is something like Asteroids, not a cat chasing it's tail!

Resources