Realistic rotation of a 3D model in libGDX by dragging

1.2k Views Asked by At

I'm trying to create a cube in libGDX that a user can rotate by tapping (or clicking) and dragging. I'd like it to feel as if an edge of the cube is being dragged in the direction you slide, which brings me to my problem. I need the model to rotate independently of how it is already rotated.

For instance, if the cube is positioned so that the Y axis runs vertically, a swipe to the right should rotate the cube around the Y axis. However, if another axis, say the X axis, runs vertically in the cubes current position, then the same gesture should rotate the cube around the X axis.

Further complication comes when no axis is positioned directly perpendicularly to the direction of the gesture. Will some combination of rotations on multiple axes be required?

I'm stumped by the calculations required to accomplish this, but I'm sure it's possible, if perhaps through a completely alternative method I haven't thought of. Any help or insight would be greatly appreciated!

1

There are 1 best solutions below

2
On

In this case I'd strongly recommend you to use Quaternions, since they are more independent for rotations in the 3D-Space.

However: since you should know the direction of your swipe on the screen ( a pair of X,Y Screen coordinates) you should be able to calculate a vector that represents the gesture.

In libgdx you can get a pickRay by calling the camera's method

.getPickRay(float screenX, float screenY)

We will need two points in 3D space that lie between the camera and your object's rotational-center and which represent the two screen-coordinates in order to calculate the quaternion for that rotation:

// you don't need to normalize the rays' directions since libgdx does that for you

final Ray ray1 = camera.getPickRay(oldScreenX, oldScreenY);
final Ray ray2 = camera.getPickRay(currentScreenX, currentScreenY);

// instead of 0.1 use some other values, preferably your camera.near value
// you can play with the scale value since it also represents how much of rotation you will get
final Vector3 screen1 = ray1.direction.cpy().scl(0.1).add(ray1.origin);
final Vector3 screen2 = ray2.direction.cpy().scl(0.1).add(ray2.origin);

Now that you have your two points in 3D space you can calculate two vectors representing the rotation to perform by involving the objects center:

final Vector3 cross1 = screen1.cpy().sub(myObjectsCenterPosition).nor();
final Vector3 cross2 = screen2.cpy().sub(myObjectsCenterPosition).nor();
final Quaternion rotation = new Quaternion();
rotation.setFromCross(cross1, cross2);

Since you should have a quarternion for your objects rotation you can apply your new rotation to the object's quaternion:

myObjectRotation.mulLeft(rotation);

And then rotate your object according to the object's rotation quaternion:

myModelInstance.transform.set(myObjectRotation);

I hope I didn't forget anything important.