2 axis Turret and lookat target

Hello everyone,

I’m hitting my forehead onto the table since several hours, but even the pain doesn’t solve my problem :smile:

I have a turret with this hierarchy:

DoubleLaserRifle
     ->LaserGun
             -> Foot
                    -> Axis1
                          -> Axis2
                              -> Laser1
                              -> Laser2

Axis 1 only should turn left/right, Axis 2 only up down. So basically I’d have to split the lookat into 2 separate axis.

Based upon these two scripts which I found somewhere in the forum, I tried to implement the most obvious way:

//returns -1 when to the left, 1 to the right, and 0 for forward/backward
public static float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up)
{
    Vector3 perp = Vector3.Cross(fwd, targetDir);
    float dir = Vector3.Dot(perp, up);

    if (dir > 0.0)
    {
        return 1.0f;
    }
    else if (dir < 0.0)
    {
        return -1.0f;
    }
    else
    {
         return 0.0f;
    }
}

public static float ContAngle(Vector3 fwd, Vector3 targetDir, Vector3 up)
{
    float angle = Vector3.Angle(fwd, targetDir);

    if (AngleDir(fwd, targetDir, up) == -1)
    {
        return 360 - angle;
    }
    else
    {
        return angle;
    }
}

I tried to implement the “look at” like this:

// Create a plane with the position of the LRAxis and the up of the axis.
p = new Plane(LeftRightAxis.up, LeftRightAxis.position);

// Calculate the distance between the plane and the target position.
dist = p.GetDistanceToPoint(lookTarget.position);

// Project the lookTarget position onto the plane.
lookOnPlane = lookTarget.position - LeftRightAxis.up*dist;

// Calculate the direction between the axis position and the point on the plane.
dirToLookOnPlane = lookOnPlane - LeftRightAxis.position;

// Calculate the angle between the up vector and the dir to look on plane.
angle = ContAngle(LeftRightAxis.forward, dirToLookOnPlane, LeftRightAxis.up);

// Rotate locally about this angle.
LeftRightAxis.localRotation = Quaternion.Euler(0.0f, 0.0f, angle);

The target is to make this work with whatever orientation the turret has in space, not just null rotation.

If anyone has an insight on how to make this work, I’ll open for ideas :slight_smile:

why not just use LookAt?
Example

var horizontalAxis : Transform;
var verticalAxis : Transform;
var target : Transform;

function LateUpdate () 
{
	var targetDirection : Vector3 = target.position - verticalAxis.position;
	targetDirection.y = 0;
	verticalAxis.LookAt(verticalAxis.position + targetDirection);
	horizontalAxis.LookAt(target);
}

Because that would not work with any arbritary aligned turret. The example only works if the turret is y aligned. That’s what seems to make it so hard to me :frowning:

it it easiest to align one of the axes, in this case the forward, to face your target. Your turrent can have whatever orientation you want, but just make sure that the forwards of the empty gameobjects you use as axes are aligned with the turret.

As I said, this works with any object that is world axis aligned (0 rotation), which is not usable for me. My turret foot might be placed into the world rotated by ie. 45° in X, 20° in Y and 5° in Z. By resetting the targetDirection.y to 0, the object’s pivot will align to the world orientation.

But your idea points me to an interesting direction… I’ll try something else tomorrow.

OK, I got you.
try this then

var horizontalAxis : Transform;
var verticalAxis : Transform;
var target : Transform;

function LateUpdate () 
{
	var targetDirection : Vector3 = verticalAxis.InverseTransformPoint(target.position);
	targetDirection.y = 0;
	targetDirection = verticalAxis.TransformPoint(targetDirection);
	verticalAxis.LookAt(targetDirection, verticalAxis.up);
	horizontalAxis.LookAt(target,horizontalAxis.up);
}

project attached. You can rotate the verticalAxis object.

678601–24370–$TurretLookAtProject.zip (165 KB)

4 Likes

Ok… thanks… that looks good… now I have to sort out that damn max → unity axes system problem. Forward in Max != Forward in Unity. While this can be solved for any root object, I’ll have to re-rig the turret (the turret is actually one mesh with a skeleton attached to it in order to only have 1 draw call per turret).

Great! After adjusting the orientation of the turret and the skeleton in Max and re-assigning the rig, the forward vectors match and the turret rotates as expected… phew…

Thanks ivkoni :slight_smile:

This is just what I was looking for. But I have one problem with this script: after several seconds of intense motion the horizontalAxis turns sideways.
GIF demo: http://i.imgur.com/TCoaBo9.gif

Thanks! I spent a day trying to work out the math for converting angles in different axes and I feel so dumb haha! :slight_smile: