Search code examples
unity-game-enginerotationpositiontransformquaternions

Unity Face Object With Off-center Pivot Point?


I'm trying to create a "billboard" effect where a quad/gameObject always faces a target object (the camera) around the Y axis. This is working fine as per the code below, but I want to add an optional offset to the pivot point on the X axis. So rather than rotating around the center point (default behaviour), I want the quad to rotate around a new point thats n units off of the center point, while still facing the target object.

This will run in Update().

Currently Working Code Without Offset

transform.LookAt(camera.transform, Vector3.up);
transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0); // Only affects Y Axis.

The offset I need is calculated by the function below. It is tested to be correct by moving a child GameObject by this value.

Both the leftObj and rightObj are children of the GameObject I want to be rotating.

    public float GetCenterPos()
    {
        Vector3 left = leftObj.transform.localPosition;
        Vector3 right = rightObj.transform.localPosition;

        Vector3 center = (left + right) / 2f;
        return center.x;
    }

Top Down View of My Problem enter image description here

I have tried combinations of RotateAround, but I can't figure out how to get it to face the correct object and what the pivot should be relative to the offset. I have also googled around, and I can't find a solution to this problem that I feel is relatively simple.

To recap: I don't need a rotational offset, and I don't want to add an extra parent to change the pivot like many other answers suggest. The offset gets calculated dynamically in Update.

Thank you for any help.


Solution

  • I've been tinkering with it for a while, and I came up with this solution. It's not ideal because it requires storing a reference to the starting position, which breaks some of the other movement functionality I need, but it does answer my original question.

    Before beginning the code above (either in start or before a bool flag is set, whatever) store a reference to the object's localPosition (startPos)

    Then before calling LookAt, adjust the position to take into account the offset.

    transform.localPosition = new Vector3(startPos.x + offset, transform.localPosition.y, transform.localPosition.z);
    transform.LookAt(camController.transform, Vector3.up);
    transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
    

    To clarify, the reason why I need a reference to startPos is because otherwise I would be adding the offset every frame, resulting in the object just moving constantly, rather than using a consistent value.

    I just set the startPos before and after toggling the "billboard" functionality to keep it updated. Not ideal, but it does work.