Rotation of a hand crank with mouse in 3D

Hi all, this is a problem that could be trivial for you, but I’m just stuck in a loop thinking… :eyes:

I have a crank that can be rotated by dragging the mouse around its center. Here’s the code:

float dist = Vector3.Distance(transform.position, Camera.main.transform.position);
Vector3 mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, dist);

Vector3 mouseWorld = Camera.main.ScreenToWorldPoint(mousePos);
mouseWorld.x = 0;

Quaternion targetRotation = Quaternion.LookRotation(mouseWorld - transform.position, Vector3.left);

transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

As you can see, this code works well in 2D, but in 3D doesn’t. That is, it properly works only when the crank is aligned with the world axis.

How can I turn this code in a 3D friendly version? Thank you.

Your calculation of targetRotation is finding a point in the world that probably is not in the plane that the crank can reach. Imagine a plane that is perpendicular to the axis of the crank, with the crank handle at the center of it. Now imagine the line through the screen that is behind the mouse. You want the intersection point of the handle’s plane and the mouse’s line. Currently you clamp the mouse world X to zero instead of finding that intersection.

1 Like

Thank you so much, you got me to the right path. :slight_smile:
I’ve removed the clamp of mouseWorld.x and changed the upwards parameter of lookRotation from Vector3.left to look straight into the camera. Here’s the right code:

// speed of the rotation
float rotationSpeed = 4.0f;

// distance of the crank from the camera
float dist = Vector3.Distance(transform.position, Camera.main.transform.position);

// the position of the mouse
Vector3 mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, dist);

// convert the position of the mouse from screen to world point
Vector3 mouseWorld = Camera.main.ScreenToWorldPoint(mousePos);

// the upwards of the rotation, it is the vector going from the crank position to the camera
Vector3 upwards = transform.position - Camera.main.transform.position;

// rotate the crank to look at the mouse
Quaternion targetRotation = Quaternion.LookRotation(mouseWorld - transform.position, upwards);

// smooth the rotation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

Glad you got it going. Here was my treatment from a few years back.

6201992–680924–RotateZViaDrag.unitypackage (20 KB)

2 Likes

This is the kind of forum user we need! Glad you got it working.