# How can I rotate a sphere in response to mouse movement?

I'm using jMonkeyEngine to develop a game. I'm good at scripting, but math usually goes over my head. I tried the Wiki page for Quaternion, but I was far too confused to figure this out myself :P

## My goal

I have a sphere with physics enabled, and I want to have it rotate based on mouse axis movement. I've got listeners set up properly so that in this method:

void roll(int axis, float tpf) {
Quaternion rot = this.getPhysicsRotation();
switch(axis) {
case MouseInput.AXIS_X:
// Rotate here
break;
case MouseInput.AXIS_Y:
// Rotate here
break;
}
}


an axis and a value (+/-) will be provided. Once I figure out how to modify Quaternions, I'll just use RigidBodyControl.setPhysicsRotation(Quaternion) to update the rotation.

## My Problem

I'm clueless about Quaternions.. I don't even know what method I'd be using. I assume Quaternion.add() or .mult() will be necessary.

## Solution

void roll(int axis, float tpf) {
tpf *= 10;
System.out.println("roll("+axis+","+tpf+")");
switch(axis) {
case MouseInput.AXIS_Y:
Quaternion quaternion = new Quaternion();
this.setPhysicsRotation(getPhysicsRotation().mult(quaternion.fromAngleAxis(tpf, Vector3f.UNIT_X)));
break;
case MouseInput.AXIS_X:
Quaternion q = new Quaternion();
this.setPhysicsRotation(getPhysicsRotation().mult(q.fromAngleAxis(tpf, Vector3f.UNIT_Y)));
break;
}
}


I'm not quite sure why case:MouseInput had to be swapped, but it works this way so.. shrug

• Don't have time for a full answer, but when working with quaternions it's pretty common to author your input data as euler angles (see Quaternion.fromAngles(float, float, float)). So generate a quaternion using an euler angle that you determine from your mouse input, then you'll probably want to do a multiply with the current angle. – Tetrad Oct 20 '11 at 22:17
• "but math usually goes over my head." If that's the case, are you sure you want to program graphics? It's basically all math. – Nicol Bolas Oct 20 '11 at 23:13
• Did you look at this answer? – Nicol Bolas Oct 20 '11 at 23:15
• Nicol, there's nothing wrong with attempting something new.. I've already learned a lot. Tetrad, I'll try and play with that when I'm back at my computer and get back to you. – Snailer Oct 21 '11 at 2:16

You don't really need to know stuff about quaternions for this. Consider the following:

Vector3f xAxis = sphere.worldToLocal(Vector3f.UNIT_X, null);
Quaternion quaternion = new Quaternion();
sphere.rotate(quaternion.fromAngleAxis(yRot, yAxis));


This will rotate your sphere about the x-axis for the given angle. You need to use worldToLocal because as you rotate your sphere around arbitrary axes, its local axes get rotated too.

As for why the y and x axis needed to be "swapped", you're not swapping anything, just think about it. When you're moving your mouse along the y-axis, you're rotating your sphere about the x-axis and vice versa. This is exactly what your code is saying.

• RigidBodyControl doesn't have a rotate() method, just set rotation. However, this could still work.. still not at my computer, but I'll try this out too. – Snailer Oct 21 '11 at 16:34
• Since you used setPhysicsRotation(getPhysicsRotation().mult, you don't need worldToLocal. Notice that you don't read the xAxis and yAxis variables in your code at all. – Zoltán Oct 24 '11 at 9:52
• lol, yeah.. I was just excited to get it working :p – Snailer Oct 24 '11 at 21:50

Have you considered an arcball implementation? They are relatively straightforward and produce reasonably intuitive means of manipulating objects in 3D space. Essentially, you project the mouse coordinates from the current and previous frame onto an imaginary sphere that surrounds your object (in this case, it is a sphere, so there's that) and then compute the shortest arc quaternion between the two points.

You can then convert that quaternion to a matrix to apply it. Do note that APIs choose slightly different conventions for quaternion representations and your math may need to be adjusted to account for that (I don't know what convention jMonkeyEngine employs).