Attempting solve rotation - math

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)

Related

Euler Angles to OpenGL direction vector?

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

Find angle between two points

I am trying to make an image move towards my mouse pointer. Basically, I get the angle between the points, and move along the x axis by the cosine of the angle, and move along the y axis the sine of the angle.
However, I don't have a good way of calculating the angle. I get the difference in x and the difference in y, and use arctangent of Δy/Δx. The resulting angle in quadrant 1 is correct, but the other three quadrants are wrong. Quadrant 2 ranges from -1 to -90 degrees. Quadrant 3 is always equal to quadrant 1, and quadrant 4 always equals quadrant 4. Is there an equation that I can use to find the angle between the two points from 1-360 degrees?
Note: I cannot use atan2(), and I do not know what a vector is.
// This working code is for Windows HDC mouse coordinates gives the angle back that is used in Windows. It assumes point 1 is your origin point
// Tested and working on Visual Studio 2017 using two mouse coordinates in HDC.
//
// Code to call our function.
float angler = get_angle_2points(Point1X, Point1Y, Point2X, Point2Y);
// Takes two window coordinates (points), turns them into vectors using the origin and calculates the angle around the x-axis between them.
// This function can be used for any HDC window. I.e., two mouse points.
float get_angle_2points(int p1x, int p1y, int p2x,int p2y)
{
// Make point1 the origin, and make point2 relative to the origin so we do point1 - point1, and point2-point1,
// Since we don’t need point1 for the equation to work, the equation works correctly with the origin 0,0.
int deltaY = p2y - p1y;
int deltaX = p2x - p1x; // Vector 2 is now relative to origin, the angle is the same, we have just transformed it to use the origin.
float angleInDegrees = atan2(deltaY, deltaX) * 180 / 3.141;
angleInDegrees *= -1; // Y axis is inverted in computer windows, Y goes down, so invert the angle.
//Angle returned as:
// 90
// 135 45
//
// 180 Origin 0
//
//
// -135 -45
//
// -90
// The returned angle can now be used in the C++ window function used in text angle alignment. I.e., plf->lfEscapement = angle*10;
return angleInDegrees;
}
The answers regarding atan2 are correct. For reference, here is atan2 in Scratch block form:
If you're unable to use atan2() directly, you could implement its internal calculations on your own:
atan2(y,x) = atan(y/x) if x>0
atan(y/x) + π if x<0 and y>0
atan(y/x) - π if x<0 and y<0
This is the code I use, and it seems to work perfectly fine.
atan(x/y) + (180*(y<0))
where X is the difference between the Xs of the points (x2 - x1), and Y is the difference between the Ys (y2 - y1).
atan((x2-x1)/(y1-y2)) + (180*((y1-y2)<0))

Translating Screen Coordinates [ x, y ] to Camera Pan and Tilt angles

I have a IP Camera which can PTZ. I am currently streaming live feed into the browser and want to allow user to click a point on the screen and the camera will pan and tilt so that the user clicked position will now become the center point of view.
my Camera Pan 360 degrees and Tilt from -55 to 90.
any algorithm that will guide to me achieve my goal ??
Let's start by declaring a 3D coordinate system around the camera (the origin). I will use the following: The z-axis points upwards. The x-axis is the camera direction with pan=tilt=0 and positive pan angles will move the camera towards the positive y-axis.
Then, the transform for a given pan/tilt configuration is:
T = Ry(-tilt) * Rz(pan)
This is the transform that positions our virtual image plane in 3D space. Let's keep that in mind and go to the image plane.
If we know the vertical and horizontal field of view and assume that lens distortions are already corrected, we can set up our image plane as follows: The image plane is 1 unit away from the camera (just by declaration) in the view direction. Let the center be the plane's local origin. Then, its horizontal extents are +- tan(fovx / 2) and its vertical extents are +- tan(fovy / 2).
Now, given a pixel position (x, y) in this image (origin in the top left corner), we first need to convert this location into a 3D direction. We start by calculating the local coordinates in the image plane. This is for the image's pixel width w and pixel height h:
lx = (2 * x / w - 1) * tan(fovx / 2)
ly = (-2 * y / h + 1) * tan(fovy / 2) (local y-axis points upwards)
lz = 1 (image plane is 1 unit away)
This is the ray that contains the according pixel under the assumption that there is no pan or tilt yet. But now it is time to get rid of this assumption. That's where our initial transform comes into play. We just need to transform this ray:
tx = cos(pan) * cos(tilt) * lx - cos(tilt) * sin(pan) * ly - sin(tilt) * lz
ty = sin(pan) * lx + cos(pan) * ly
tz = cos(pan) * sin(tilt) * lx - sin(pan) * sin(tilt) * ly + cos(tilt) * lz
The resulting direction now describes the ray that contains the specified pixel in the global coordinate system that we set up in the beginning. All that's left is calculate the new pan/tilt parameters:
tilt = atan2(tz, tx)
pan = asin(ty / sqrt(tx^2 + ty^2 + tz^2))

How to calculate the angles of the projection in 3d for an object to step at given point?

I need to calculate the angles to through the ball in that direction for a given speed and the point where it should land after thrown.
The horizontal angle is easy(We know both start and step points).How to calculate the vertical angle of projection.There is gravy applying on object.
Time of travel will be usual as bowling time(time between ball release and occurring step) as per video.
Is there a way directly in unity3d?
Watch this video for 8 seconds for clear understating of this question.
According to the Wikipedia page Trajectory of a projectile, the "Angle of reach" (The angle you want to know) is calculated as follows:
θ = 1/2 * arcsin(gd/v²)
In this formula, g is the gravitational constant 9.81, d is the distance you want the projectile to travel, and v is the velocity at which the object is thrown.
Code to calculate this could look something like this:
float ThrowAngle(Vector3 destination, float velocity)
{
const float g = 9.81f;
float distance = Vector3.Distance(transform.position, destination);
//assuming you want degrees, otherwise just drop the Rad2Deg.
return Mathf.Rad2Deg * (0.5f * Asin((g*distance)/Mathf.Pow(velocity, 2f)));
}
This will give you the angle assuming no air resistance etc. exist in your game.
If your destination and your "throwing point" are not at the same height, you may want to set both to y=0 first, otherwise, errors may occur.
EDIT:
Considering that your launch point is higher up than the destination, this formula from the same page should work:
θ = arctan(v² (+/-) √(v^4-g(gx² + 2yv²))/gx)
Here, x is the range, or distance, and y is the altitude (relative to the launch point).
Code:
float ThrowAngle(Vector3 start, Vector3 destination, float v)
{
const float g = 9.81f;
float xzd = Mathf.Sqrt(Mathf.Pow(destination.x - start.x, 2) + Mathf.Pow(destination.z - start.z, 2));
float yd = destination.y - start.y;
//assuming you want degrees, otherwise just drop the Rad2Deg. Split into two lines for better readability.
float sqrt = (Mathf.Pow(v,4) - g * (g*Mathf.Pow(xzd,2) + 2*yd*Mathf.Pow(v,2))/g*xzd);
//you could also implement a solution which uses both values in some way, but I left that out for simplicity.
return Mathf.Atan(Mathf.Pow(v, 2) + sqrt);
}

Limit camera pitch

How can I efficiently limit camera pitch when I have only camera quaternion? Do I have to convert to euler angles and then back to quaternion or is there any other way?
If the camera never has any roll (as is common in lots of games, such as first person shooters), then the solution is simple. If there is roll, then there's an additional step involved. I'll start with what to do if there is no roll, and generalize the solution to what to do if there is.
Let qc be the camera rotation. Let qy a rotation with the same yaw as qc, but with zero pitch. If there is no roll, the camera rotation is a yaw rotation followed by a pitch rotation:
qc = qp * qy
We can recover the pitch rotation qp as the rotation from qy to qc:
qp = qc * qy^-1
The trick, then, is to construct qy, so we can plug it into the above equation to solve for qp. Let vc be the unit vector pointing out of the lens of the camera, or the "forward vector". Let vy be the same vector, but projected to the horizontal plane and normalized. Finally, let v0 be the forward vector when the camera rotation qc is the identity rotation. The rotation that rotates v0 into vy is the yaw rotation. The angle can be given as:
yaw = asin(Norm(cross(v0, vy)))
The corresponding yaw rotation is:
qy = { cos(yaw/2), up * sin(yaw/2) }
Where "up" is the unit vector in the up direction, aka the axis for yaw rotations. Plug this into qp = qy^-1 * qc above to get pitch quaternion qp. Finally, get the pitch angle from qp as:
pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]]))
Where "right" is the unit vector in the right direction, aka the axis for pitch rotations.
Like I said, things get more complicated if the camera also has roll, but the general strategy is the same. You formulate the camera rotation as a product of rotation components, then isolate the component you want (in this case, pitch). For example, if the euler sequence you use to define "pitch" is the common yaw-pitch-roll sequence, you define qc as:
qc = qr * qp * qy
We can define a variable qx to be the combined pitch and roll rotations:
qx = qr * qp
We can now write qc as:
qc = qx * qy
We already know how to solve for qx in this form, by retracing the steps we used above to solve for qp. Rearranging the definition for qx, we get:
qp = qr^-1 * qx
We just solved for qx, so to solve for the pitch rotation qp, we only need the roll qr. We can construct it using vectors as we did previously. Let vc be the forward vector again. The roll will be a rotation around this vector. Let vu be the camera's up vector (in world coordinates), and let vu0 be the camera's up vector with zero roll. We can construct vu0 by projecting the global up vector to the plane perpendicular to vc, then normalizing. The roll rotation qr is then the rotation from vu0 to vu. The axis of this rotation is the forward vector vc. The roll angle is
roll = asin(Dot(vc, cross(vu0, vu)))
The corresponding quaternion is:
qr = { cos(roll/2), forward * sin(roll/2) }
Where "forward" is the axis of roll rotations.
The pitch is just one component of the full rotation, so if you want to think about your rotation like that, you'd better store the pitch separately, possibly using Euler angles.
Just converting to Euler angles and back when you need to limit the movement might not work too well, since you'l need to remember the last frame (if you have any) to see if you passed the limit, and in what direction.
As I see it, the main point of quaternions is that you don't need to bother with limits like that. Everything just works without any singularities. Why exactly do you want to limit the pitch?
Camera rotation quaternions can be defined as:
vector A = [x, y, z]
Q.x = A.x * sin(theta/2)
Q.y = A.y * sin(theta/2)
Q.z = A.z * sin(theta/2)
Q.w = cos(theta/2)
Where A is the position and theta is the angle you want to rotate the camera (adjust the pitch).
So if you have the quaternion available you can limit the angle of pitch by verifying each time if the rotation angle plus/minus the actual angle is ok.
I think you can avoid conversion if you set your limits as
+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2)
As cosine is an continuous function this is supposed to work.
If you could post the code you're actually using maybe we can help a little more.
I may be a little late to the party, but this is how I solved it:
// "Up" = local vector -> rotation * Vector3.UnitY
// "Forward" = local vector -> rotation * Vector3.UnitZ
// "Right" = local vector -> rotation * Vector3.UnitX
public void Rotate(Vector3 axis, float angle)
{
if (LerpRotation)
{
RotationTarget *= Quaternion.FromAxisAngle(axis, angle);
}
else
{
Rotation *= Quaternion.FromAxisAngle(axis, angle);
}
//Locking the Pitch in 180°
float a = Vector3.CalculateAngle(Vector3.UnitY, Up);
float sign = Math.Sign(Forward.Y);
float delta = (float)Math.PI / 2 - a;
if(delta < 0)
Rotation *= Quaternion.FromAxisAngle(Right, delta * sign);
}

Resources