Angle of 2 Vector3 on one axis

Hey there!

So this is my situation: I have a classic turret made out of a turretBase (that rotates on Y only) and a turretBody (that rotates on X only) which is a child of the turretBase. The turret is attached to a ship that rotates on all axis.

When I select a target, I want the base to rotate towards it on Y and the body to rotate towards the target on X. I need to do all this using angles, and transform.RotateAround, because I am also imposing limits on the turret (so it does not shoot through the ship).

So my idea for the base was to find the angle between base.forward and the target direction (which is target.position - turretBase.position). The problem is that this angle has to be only in XZ plane (so an Y angle). What I did was this:

var targetDirection = target.position - turretBase.position;
			
			targetDirection.y = turretBase.forward.y;
			yAngleToTarget = Vector3.Angle(turretBase.forward, targetDirection);

Well, as expected, that angle is not only on Y, so I can’t use it.

So my question is: having 2 Vector3s, how do I get the Y angle between them, relative to the first vector?

Thanks in advance!

PS: I also tried this:

var targetDirection = target.position - turretBase.position;
var angleOnY = Mathf.Asin(Vector3.Cross(targetDirection, turretBase.forward).y) * Mathf.Rad2Deg;

and it works great at times, problem is it often causes an “!IsFinite(outDistanceAlongView)” error. Probably division by 0, somewhere, though I can’t be sure.

I found this solutions to be locked in a range of -90°-90° so here’s my solution:

var targetDirection = targetPosition - turretTransform.position;

targetDirection = turretTransform.InverseTransformDirection(targetDirection);

var angleOnY = Mathf.Atan2( targetDirection.z, targetDirection.x ) * Mathf.Rad2Deg;

// You may have to +/- 90 to the last angle but this works for me in 360°.
// I use it for directional hit markers in my shooter for turning 3d into 2d screen space

Hope that helps someone as this is the page I found on Google.

One note: V3.Angle can’t tell left from right.

Sometimes easier to put everything in the turret’s local coords. This assumes turretBase has +z pointing the way it shoots:

V3 targDir = targPos - myPos; // your same code
targDir = turretBase.InverseTransformDirection(targDir);

targDir.y = 0; // if you want to get the Y-angle

The hardest part is realizing that targDir is now using the turret’s red/green/blue arrows (with the base as 000.) V3.Angle(V3.forward, targDir gives the spin around the turrets local green up arrow, AND, can just check if(targDir.x<0) to get left/right.

The vectors must be normalized for Vector3.Cross to return a value equal to the sine of the angle. Since turretBase.forward already is a normalized vector, you only have to normalize targetDirection :

var targetDirection = target.position - turretBase.position;
var angleOnY = Mathf.Asin(Vector3.Cross(targetDirection.normalized, turretBase.forward).y) * Mathf.Rad2Deg;

This returns a signed angle about the axis Y; if you use Cross().x, the angle returned is about the axis X, and so on.