tsa icon

Arcball rotation with GLKit

A while back Apple finally added some basic 3d classes with GLKit. They included vectors, matrices, and even quaternions. Awesome! Time to do some arcball rotation! Well, I googled myself silly and couldn’t dig up a single sample of using these classes to do a simple object rotation. There are tons of articles about quaternions, gimbal lock, SLERP, and so forth, but I couldn’t locate a basic iOS arcball example. The clearest code I could find is here, but it’s straight C and uses its own Vector and Matrix classes. Arguably straight C can be faster, but wouldn’t it be great to get this all nice and Objective? Well, below is a simple snippet based on the above that uses GLKit. You can plug this right into the Xcode OpenGL Game template, et voila.

 
#define RADIANS_PER_PIXEL (M_PI / 320.f)
 
/**
 * do this in viewDidLoad
 *
 * these are class variables:
 
	CGPoint iniLocation;
	GLKQuaternion quarternion;
 
 */
- (void) initArcBall
{
	quarternion = GLKQuaternionMake(0.f, 0.f, 0.f, 1.f);
	iniLocation = CGPointMake(0.f, 0.f);
}
 
/**
 * do this in update
 
 // skip auto rotation
 //baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _rotation, 0.0f, 1.0f, 0.0f);
 
 // rotate with quaternion instead
 [self rotateMatrixWithArcBall:&baseModelViewMatrix];
 
 */
- (void) rotateMatrixWithArcBall:(GLKMatrix4 *)matrix
{
	GLKVector3 axis = GLKQuaternionAxis(quarternion);
	float angle = GLKQuaternionAngle(quarternion);
	if( angle != 0.f )
		*matrix = GLKMatrix4Rotate(*matrix, angle, axis.x, axis.y, axis.z);
}
 
// ------------------------------------------------------------------------------------------
 
- (void) rotateQuaternionWithVector:(CGPoint)delta
{
	GLKVector3 up = GLKVector3Make(0.f, 1.f, 0.f);
	GLKVector3 right = GLKVector3Make(-1.f, 0.f, 0.f);
 
	up = GLKQuaternionRotateVector3( GLKQuaternionInvert(quarternion), up );
	quarternion = GLKQuaternionMultiply(quarternion, GLKQuaternionMakeWithAngleAndVector3Axis(delta.x * RADIANS_PER_PIXEL, up));
 
	right = GLKQuaternionRotateVector3( GLKQuaternionInvert(quarternion), right );
	quarternion = GLKQuaternionMultiply(quarternion, GLKQuaternionMakeWithAngleAndVector3Axis(delta.y * RADIANS_PER_PIXEL, right));
}
 
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	UITouch *touch = [touches anyObject];
	CGPoint location = [touch locationInView:self.view];
 
	iniLocation = location;	
}
 
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
	UITouch *touch = [touches anyObject];
	CGPoint location = [touch locationInView:self.view];
 
	// get touch delta
	CGPoint delta = CGPointMake(location.x - iniLocation.x, -(location.y - iniLocation.y));
	iniLocation = location;
 
	// rotate
	[self rotateQuaternionWithVector:delta];
}

Strange?

Tags: ,

5 Responses

  1. James says:

    This is great! Simple and effective.

    Cheers man

  2. Karl says:

    Thanks for this, been looking for something like this for a while. Can’t quite get it to work just plugging it straight in – probably missing something really simple.

    I can see what’s supposed to happen so it’s helped me enormously anyway – thanks again.

  3. christoph halang says:

    Hey, thank you for your tutorial. Very elegant and helpful.

    A small remark: The source code above rotates the cube forever once it is touched. To avoid this behaviour change the following line in rotateMatrixWithArcBall:

    *matrix = GLKMatrix4Rotate(*matrix, angle, axis.x, axis.y, axis.z);
    to

    *matrix = GLKMatrix4MakeRotation(angle, axis.x, axis.y, axis.z);

    This creates a new matrix that represents the orientation that is stored in the quarternion instead of constantly multiplying the current rotation matrix with a rotation matrix.

  4. christoph halang says:

    Another remark: This is not an actual arcball implementation. This code only maps dX and dY to rotation on X and Y axis. The arcball uses an virtual ball as an interaction metapher. Touch points are mapped from the 2D screen to the surface of a sphere. A rotation axis and angle is calculated and used to create the quaternion / matrix. The theory is explained here: http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Arcball

Leave a Reply