guess people missed the “independent of parent orientation”… i.e. upside down, right side up, on the side etc. 
I’ve been trying to figure this out, and I’ve gotten a little way there I think. Script is far from complete but the “right way up” and “up side down” turrets both track the orbiting target, you can rotate their parent “ship” and they continue to track until the rotation gets to almost 90 degs, then they go a little mental, 90degs needs to be handled since there isn’t a rotation for the turret to track a point directly above it (if you are going to put in elevation limits on the barrel I guess that would get rolled into this part of the code)… script goes on the TurretBase gameobjects.
this was my test project, magenta cube is the gizmo rendering at 0,0,0 (so off centre “ship”), sphere is a target set to orbit the “ship”. TurretBase are prefabs, one is rotated 180 but they are running the same code.
using UnityEngine;
using System.Collections;
public class TurretBase : MonoBehaviour
{
public Transform target;
public Transform lateralTurret;
public Transform barrel;
public Vector3 effectiveTargetPosition;
public Vector3 effectiveTargetElevation;
void Start()
{
lateralTurret = transform.Find("Turret");
barrel = lateralTurret.Find("Barrel");
}
void Update()
{
if(target)
{
// work out the point where the target is in the plane of the turret
LinePlaneIntersection(out effectiveTargetPosition, target.position, lateralTurret.up, lateralTurret.up, lateralTurret.position);
// direction from turret's point of view
Vector3 targetDirection = effectiveTargetPosition - lateralTurret.position;
// amount to turn by
float forwardAngle = Vector3.Angle(lateralTurret.forward, targetDirection);
// rotate
lateralTurret.RotateAround(lateralTurret.position, lateralTurret.up, forwardAngle * AngleDir(lateralTurret.forward, targetDirection, lateralTurret.up));
Debug.DrawRay(target.position, barrel.right * 50, Color.yellow);
DrawPlane(barrel.right * 50, barrel.position, Color.green);
// work out the point where the target is in the plane of the barrel
LinePlaneIntersection(out effectiveTargetElevation, target.position, barrel.right, barrel.right, barrel.position);
// direction from turret's point of view
targetDirection = effectiveTargetElevation - barrel.position;
// amount to turn by
forwardAngle = Vector3.Angle(barrel.forward, targetDirection);
// rotate
barrel.RotateAround(barrel.position, barrel.right, forwardAngle * AngleDir(barrel.forward, targetDirection, barrel.right));
}
}
// taken from somewhere on the web... didn't make a note =(
// figures out left/right side to overcome lack of perspective in most rotation functions.
public float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up)
{
Vector3 perp = Vector3.Cross(fwd, targetDir);
float dir = Vector3.Dot(perp, up);
if (dir > 0.0f)
{
return 1.0f;
}
else if (dir < 0.0f)
{
return -1.0f;
}
else
{
return 0.0f;
}
}
public void SetTarget(Transform t)
{
target = t;
}
public void OnDrawGizmos()
{
// draw magenta cube where target point is in turrets plane (viewed from above in ortho camera should always be in line with target)
Gizmos.color = Color.magenta;
Gizmos.DrawCube(effectiveTargetPosition, new Vector3(0.2f, 0.2f, 0.2f));
// draw magenta cube where target point is in turrets plane (viewed from above in ortho camera should always be in line with target)
Gizmos.color = Color.cyan;
Gizmos.DrawCube(effectiveTargetElevation, new Vector3(0.2f, 0.2f, 0.2f));
}
// intersection function from http://wiki.unity3d.com/index.php/3d_Math_functions
public static bool LinePlaneIntersection(out Vector3 intersection, Vector3 linePoint, Vector3 lineVec, Vector3 planeNormal, Vector3 planePoint)
{
float length;
float dotNumerator;
float dotDenominator;
Vector3 vector;
intersection = Vector3.zero;
//calculate the distance between the linePoint and the line-plane intersection point
dotNumerator = Vector3.Dot((planePoint - linePoint), planeNormal);
dotDenominator = Vector3.Dot(lineVec, planeNormal);
//line and plane are not parallel
if (dotDenominator != 0.0f)
{
length = dotNumerator / dotDenominator;
//create a vector from the linePoint to the intersection point
vector = SetVectorLength(lineVec, length);
//get the coordinates of the line-plane intersection point
intersection = linePoint + vector;
return true;
}
//output not valid
else
{
return false;
}
}
//create a vector of direction "vector" with length "size" from http://wiki.unity3d.com/index.php/3d_Math_functions
public static Vector3 SetVectorLength(Vector3 vector, float size)
{
//normalize the vector
Vector3 vectorNormalized = Vector3.Normalize(vector);
//scale the vector
return vectorNormalized *= size;
}
// debug draw plane from unity answers: http://answers.unity3d.com/questions/467458/how-to-debug-drawing-plane.html
public void DrawPlane(Vector3 normal, Vector3 position, Color c)
{
Vector3 v3 ;
if (normal.normalized != Vector3.forward)
v3 = Vector3.Cross(normal, Vector3.forward).normalized * normal.magnitude;
else
v3 = Vector3.Cross(normal, Vector3.up).normalized * normal.magnitude;;
Vector3 corner0 = position + v3;
Vector3 corner2 = position - v3;
Quaternion q = Quaternion.AngleAxis(90.0f, normal);
v3 = q * v3;
Vector3 corner1 = position + v3;
Vector3 corner3 = position - v3;
Debug.DrawLine(corner0, corner2, c);
Debug.DrawLine(corner1, corner3, c);
Debug.DrawLine(corner0, corner1, c);
Debug.DrawLine(corner1, corner2, c);
Debug.DrawLine(corner2, corner3, c);
Debug.DrawLine(corner3, corner0, c);
Debug.DrawRay(position, normal, Color.red);
}
}
edit: added in the turret barrel elevation and corrected a mix up between world up and local up in the rotation. Also added a few more debugs into the scene view so it’s a little more clear what’s going on.