0
\$\begingroup\$

I was hoping to get some help with a LookRotation() issue I've been having in Unity/C#.

In my project I have a target that attaches to the camera when clicked on (think of it like grabbing an object off a shelf with your hand and pulling it close). While the object is being pulled towards the camera it needs to remain facing the camera at all times including when the camera itself rotates; either horizontally or vertically. The object can also be dragged on screen with the mouse.

To ensure the object faces the camera I basically use the following code:

Vector3 direction = (target.transform.position - Camera.main.transform.position).normalized;
Quaternion lookTarget = Quaternion.LookRotation(direction, Vector3.up);
target.transform.rotation = lookTarget;

While this will ensure that the object remains facing the camera it also causes the target to roll in its forward axis when the camera rotates up or down. If the target is grabbed while the camera x rotation is off centre, the target will also have increased roll. The greater the camera rotation is in x, the greater the target will roll.

In the image below I've grabbed the left object and attached it to the left side of the screen; note the roll introduced in the 2nd image compared with the first. The rotation of the object in image 1 is what I would like to replicate in image 2.

screenshot demonstrating problem

I note that the following code can correctly adjust the roll as desired (10 degrees in this case):

lookTarget *= Quaternion.AngleAxis(10f, Vector3.forward);

However, I'm unsure how much to adjust the roll by as the roll amount will vary based on the camera's rotation in x. I'm not sure what the relationship is between the two or how to calculate it.

I've also tried other things like multiplying the lookTarget value by the camera rotation and using Vector3.right as the upwards parameter in the LookRotation() method (works but not for different y camera rotation values).

Any help would be great to hopefully understand this better and resolve the issue.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Try this. At the moment you grab the object:

upInView = Camera.main.transform.InverseTransformDirection(pickedObject.transform.up);

This remembers how the object's "up" vector was tilted relative to the view orientation at the moment of the grab.

Then each frame the object is held:

Vector3 viewRelativeUp = Camera.main.transform.rotation * upInView;
pickedObject.transform.rotation = Quaternion.LookRotation(direction, viewRelativeUp);

This keeps the object's "up" direction relative to the camera view orientation fixed.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks. That definitely works to keep the object roll stable as the camera rotates or when the object is dragged. The only remaining issue is that the rotation of the camera when the object is grabbed determines the object's initial roll amount. So grabbing the object while the camera is tilted compared to when the camera's rotation is at zero produces a different initial roll amount. I can use Quaternion.AngleAxis on the object's forward axis to adjust but not sure how much to adjust by. \$\endgroup\$ Commented Sep 29, 2022 at 4:38
  • \$\begingroup\$ If you're OK with a snap in rotation on pickup, try using Camera.main.transform.up instead of the view relative up. Also, keep in mind that the Camera.main getter does a search, so you probably want to cache your camera in a member variable for faster access. \$\endgroup\$
    – DMGregory
    Commented Sep 29, 2022 at 11:26
  • \$\begingroup\$ Ah. Yes I do use a cached reference for the camera already so I'll make that change. Also switched to the Camera.main. transform.up direction and use that in combination with a Quaternion.RotateTowards() for a smooth rotation. All works a treat now. Thanks for your help :) \$\endgroup\$ Commented Sep 30, 2022 at 1:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .