A simple rotation problem, how to limit a rotation around a certain axis?

I want to limit the “pitch” of an object to a fixed region.

My scenario:
I have a panel and a camera.

When the player (camera) is far away I want the panel to look towards the player, but only rotating around the y axis (so only “left-right”). This already works using this code:

Vector3 aDir =  panel.transform.position - camera.transform.position;
aDir.y = 0;
Quaternion aRotation = Quaternion.LookRotation(aDir, Vector3.up);

As the camera gets closer I want the panel to rotate so it looks directly into the camera.
This also works already. Using this code:

Vector3 bDir = camera.transform.forward;
Quaternion bRotation = Quaternion.LookRotation(bDir);

Now my problem:
When the camera is almost directly above the object, the panel tilts backwards towards an (almost) 90° angle.
Which makes perfect sense as that’s how I coded it. But its not what I want.

Instead I want to limit how much the panel can tilt “forwards” and “backwards”.
I looked up the right word and specifically I want to limit the “pitch” (so the rotation around the panel’s transform.right direction).
The panel should at most rotate -MaxAngle degrees backwards and at most +MaxAngle degrees forwards.

However I can’t seem to figure out how to do this.

My initial approach was to simply get the rotation of the Quaternion around the transform.right axis.
But there’s no method to get the angle around a user-specified axis.
There is ToAngleAxis but that gives both axis as well as angle as a result, which is not what I want at all.
I would need a method that calculates the rotation around an axis I give to it.

Then I could simply clamp the angle to my specified limits and then create the new rotation using something like: aRot * Quaternion.AngleAxis(transform.forward, clampedAngle);
where aRot is the old rotation mentioned above (the one where the panel only rotates around the Y axis).
So I’d essentially construct the “pitch” part of the rotation myself.

It seems like I’m missing something.
Does anyone have an idea how to do this?
I feel like it should be really simple and I’m just not seeing it right now.

You can use Quaternion.Angle to get the angle between two quaternions. Just store your initial rotation & compare your new rotation to that.

Ohh, there are static methods on Quaternion as well, not just instance methods. I totally forgot.
Thanks man!!

Angle is helpful.
But there’s also RotateTowards which has an “maxAngleDelta” parameter which was exactly what I needed :slight_smile:

Now that I think about it even more; in theory one could also calculate the direction vectors between the two look directions, figure out the angle between them, then find the “right” axis (using Vector3.Cross) and then manually rotating the transform.

I wonder what other ways there are to do this and if one is especially fast (performance wise)