gyro implementation on iPhone3GS, iPad
- your device coordinate X:(1,0,0), Y:(0,1,0), Z:(0,0,1)
- adjust 'North direction' to make right-angle with 'Gravity'
- move your North-Direction to Gravity-space coordinates
- make right-angle with gravity-direciton
- move back North-direction to real-world-space
- Make matrix (OpenGL view-matrix)
- assuming you receiving device heading by [CLLocationManagerDelegater]
float headingX; // your device Heading X
float headingY; // your device Heading Y
float headingZ; // your device Heading Z
float headingY; // your device Heading Y
float headingZ; // your device Heading Z
- assuming you receiving acceleration by [UIAccelerometerDelegate]
float accelerationX; // accelerometer x
float accelerationY; // accelerometer y
float accelerationZ; // accelerometer z
- note1 : heading always pointed North Pole (ie: magnetic north)
- note2 : accelerometer always pointed center of earth (ie: gravity)
- than you can calculate North-Direction in your position.
vector3 north(headingX, headingY, headingZ); // north direction
vector3 gravity(accelerationX, accelerationY, accelerationZ); // gravity direction
vector3 deviceUp = vector3(0,1,0); // device up direction
vector3 gravity(accelerationX, accelerationY, accelerationZ); // gravity direction
vector3 deviceUp = vector3(0,1,0); // device up direction

- calculate rotation angle between device(your position) to gravity (earth center)
vector3 rotationAxis = corss(deviceUp, gravity); // rotationAxis (cross-product of deviceUp, gravity-direction)
float rotationAngle = acos( dot( deviceUp, gravity )); // rotationAngle (arccosine of dot-product of (deviceUp, gravity))
quaternion localToGravity = (rotationAxis, rotationAngle); // make quaternion with axis, angle
float rotationAngle = acos( dot( deviceUp, gravity )); // rotationAngle (arccosine of dot-product of (deviceUp, gravity))
quaternion localToGravity = (rotationAxis, rotationAngle); // make quaternion with axis, angle
- How to build a quaternion with angle, axis ?
http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation#Quaternion_from_axis-angle
- move your 'North-direction' to 'Gravity space coordinates'
vector3 rightAngleHeading = north * localToGravity.Inverse();
- ignoring theta angle to make right-angle of your local-coordinates
rightAngleHeading.y = 0; // it is just ignoring theta angle between 'north', 'device-up'
- Move back your local coordination to 'real-world space coordinates'
rightAngleHeading = rightAngleHeading * localToGravity;
- Now calculate your real-world coordination X,Y,Z
vector3 worldAxisY = -gravity;
vector3 worldAxisZ = normalize(-rightAngleHeading);
vector3 worldAxisX = normalize(cross(worldAxisY, worldAxisZ)); // cross-product worldAxisY, worldAxisZ, than normalize

- Then, make matrix of Your-Local-Coordinate to 'Real-World-Coordinate'
matrix3x3 viewMatrix{
worldAxisX.x, worldAxisX.y, worldAxisX.z,worldAxisY.x, worldAxisY.y, worldAxisY.z,worldAxisZ.x, worldAxisZ.y, worldAxisZ.z
};or matrix4x4matrix4x4 viewMatrix{
worldAxisX.x, worldAxisX.y, worldAxisX.z, 0worldAxisY.x, worldAxisY.y, worldAxisY.z, 0worldAxisZ.x, worldAxisZ.y, worldAxisZ.z, 00, 0, 0, 1
}
- or you can set up your own transform-matrix with Axis
- refer to http://www.songho.ca/opengl/gl_transform.html#matrix
| SAMPLE CODE | |
|---|---|
| declaration | UIAccelerationValue accelerationX; UIAccelerationValue accelerationY; UIAccelerationValue accelerationZ; CLHeadingComponentValue headingX; CLHeadingComponentValue headingY; CLHeadingComponentValue headingZ; |
| constant | const double lowpassFilter = 0.1f; const double IGL_PI = 3.14159265358979323846f; |
| getting device-heading | - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { if (newHeading.headingAccuracy > 0) { headingX = headingX * (1.0f - lowpassFilter) + newHeading.x * lowpassFilter; headingY = headingY * (1.0f - lowpassFilter) + newHeading.y * lowpassFilter; headingZ = headingZ * (1.0f - lowpassFilter) + newHeading.z * lowpassFilter; } } |
| getting gravity-direction | - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { accelerationX = accelerationX * (1.0f - lowpassFilter) + acceleration.x * lowpassFilter; accelerationY = accelerationY * (1.0f - lowpassFilter) + acceleration.y * lowpassFilter; accelerationZ = accelerationZ * (1.0f - lowpassFilter) + acceleration.z * lowpassFilter; } |
| calculating view matrix | IGMatrix3 IGApplicationContextImpl::GetSystemRotation(void) const { if ([[UIApplication sharedApplication].delegate isKindOfClass:[IGApplicationDelegate class]]) { IGApplicationDelegate* appDelegate = (IGApplicationDelegate*)[UIApplication sharedApplication].delegate; IGVector3 deviceHeading = IGVector3(appDelegate.headingX, appDelegate.headingY, appDelegate.headingZ).Normalize(); IGVector3 deviceGravity = IGVector3(appDelegate.accelerationX, appDelegate.accelerationY, appDelegate.accelerationZ).Normalize(); // 로컬 좌표를 gravity 로 변환하기 위한 타겟 (중력과 가까운 y 축 방향으로 설정한다) IGVector3 rotationTarget = IGVector3::Dot(IGVector3(0,1,0), deviceGravity) > 0.0 ? IGVector3(0,1,0) : IGVector3(0,-1,0); // 로컬좌표가 gravity 로 이동하는 회전을 구한다. IGQuaternion localToGravity(IGVector3::Cross(rotationTarget, deviceGravity), acos(IGVector3::Dot(rotationTarget, deviceGravity))); // rightAngledHeading: 중력방향과 직각을 이루는 북쪽(heading) IGVector3 rightAngledHeading = deviceHeading * IGQuaternion(localToGravity).Inverse(); // heading 을 로컬 좌표로 변환한다. rightAngledHeading.y = 0; // 로컬 heading 을 x,z 평면으로 프로젝션 rightAngledHeading.Rotate(localToGravity); // 다시 현실 좌표로 원위치 (이제 중력과 직각이 된다) IGVector3 worldAxisY = IGVector3(-deviceGravity); IGVector3 worldAxisZ = IGVector3(-rightAngledHeading).Normalize(); IGVector3 worldAxisX = IGVector3::Cross(worldAxisY, worldAxisZ).Normalize(); // X 축 좌표는 Y 축과 Z 축의 외적 IGMatrix3 deviceRotate = IGMatrix3::identity; switch ([(IGApplicationViewController*)appDelegate.viewController orientation]) { case UIInterfaceOrientationPortraitUpsideDown: deviceRotate *= IGLinearTransform3().Identity().Rotate(IGVector3(0,0,1), IGL_PI); break; case UIInterfaceOrientationLandscapeLeft: deviceRotate *= IGLinearTransform3().Identity().Rotate(IGVector3(0,0,-1), IGL_PI/2); break; case UIInterfaceOrientationLandscapeRight: deviceRotate *= IGLinearTransform3().Identity().Rotate(IGVector3(0,0,1), IGL_PI/2); break; } return IGMatrix3(worldAxisX, worldAxisY, worldAxisZ) * deviceRotate; } return IGMatrix3().Identity(); } |
| Note | IGApplicationDelegate is just UIApplicationDelegate object (not important whatever), just keep tracking device orientation. IGVector3 is vector3 object (contains float x,y,z) IGQuaternion is quaternion object (contains float x,y,z,w). You must be able to build with rotation angle, axis IGMatrix3 is matrix 3x3 object. |