views:

418

answers:

3

I'm trying to display an object in the view which can be rotated naturally by dragging the cursor/touchscreen. At the moment I've got X and Y rotation of an object like this

glRotatef(rotateX, 0f, 1f, 0f); // Dragging along X, so spin around Y axis
glRotatef(rotateY, 1f, 0f, 0f);

I understand why this doesn't do what I want it to do (e.g. if you spin it right 180 degrees, up and down spinning gets reversed). I just can't figure out a way for both directions to stay left-right and up-down relative to the viewer.

I can assume that the camera is fixed and looking along the Z axis. Any ideas?

+2  A: 

Your best bet is to implement a Quaternion-based rotation. In the Quaternion world, every time you rotate, it will be axis-aligned to the axis you specify, without being affected by the previous rotations. This is also why it doesn't suffer from Gimbal Lock.

I've found these pages helpful for implementing quaternions:

Good luck. I'm sure there are other solutions, but this one is one of the cleanest you can have.

Xavier Ho
Thanks - I suspected the scary world of quaternions might be involved in this. I'll report back with results.
Nick
I shall await your victory.
Xavier Ho
Success! After a few different attempts at manipulating quaternions, I've found it works well to create a vector representing the current mouse/finger drag, then calculate the right angle of that to act as the axis of rotation. Then using the magnitude of the vector as the rotation angle, you can create a Quaternion of that.If anyone is very interested in some messy Android code that does this, let me know.Thanks Xavier.
Nick
Ah yes, smart idea. How are you calculating the "right angle"? Are you rotating the x, y, z to y, z, x, and setting the first value to its negation? =]. I'm glad you got something working. I'll have to look into Android app-making some time. I'm still tacking the beast which is OpenGL.
Xavier Ho
I am just taking the x and y of the drag to create a vector (-y,-x,0) - then grabbing the magnitude of that before normalising it to put into the quaternion. I found the Java implemention of Quaternion on some site since the Android runtime library doesn't include Java3D classes such as Quat4f.
Nick
Right, you only need to work with x and y since the screen is on the xy-plane. Nice.
Xavier Ho
+1  A: 

Nick, which Quaterion class are you using? I'm struggling with this right now for an android app.

Peter
Hi Peter, I think I used this class: http://www.koders.com/java/fid9C4BF6391E91B53E3F3B672132B4F928432FD49C.aspx and I modified it slightly to allow it to convert itself to a Matrix representation, resulting in this: http://pastebin.org/415854
Nick
+1  A: 

I decided to put my DragControl class up for download, along with the Quaternion support class. Once you have an OpenGL canvas looking along the Z axis at some object, it should be little effort to drop this in. It's just the plain .java files currently, no built library.

DragControl handles pretty much everything including finger flinging, so you can send your object spinning with a flick.

http://github.com/halfninja/android-dragcontrol3d

In activity setup:

dragControl = new DragControl();
glView.setOnTouchListener(dragControl);

When updating object rotation in a loop:

Quaternion rotation = dragControl.currentRotation();

If you make any cool modifications I'd like to see them.

Nick