Gyroscope gives developers a wide range of exciting control variations. But when it comes to its integration and implementation of camera controller, lots of strange and magic things happen. Developers have to deal with different device orientations, initial camera positions and, of course, quaternions. I’m glad to share my experience and describe how we solved these problems at Heyworks. Hopefully, this will save efforts and nerves of those, who work with gyroscope for the first time.
In my example I want to demonstrate how to implement the following features in camera controller:
- Device’s screen is supposed to work as a “window” into the virtual world so, that the turning the device around user could observe it.
- It will support autorotation and work on every device orientation.
- You will be able to detach the controller from camera, change its rotation and position from the code (play camera animation for example) and then attach controller back without noticeable hitches.
- It will keep virtual world up axis in parallel with real world up axis and will recalibrate horizontal rotation.
The first problem we solve is different coordinate system reference types that are used in iOS devices and Unity3D: left-handed and right-handed. In order to convert quaternion from one system to another, let’s use the following function:
private static Quaternion ConvertRotation(Quaternion q) { return new Quaternion(q.x, q.y, -q.z, -q.w); }
Now we can use the following line to calculate camera rotation:
transform.rotation = ConvertRotation(Input.gyro.attitude);
Another problem to deal with is supporting different orientations (was solved internally by Unity developers in Unity 4) which is fixed by the following function for each orientation:
private Quaternion GetRotFix() { if (Screen.orientation == ScreenOrientation.Portrait) return Quaternion.identity; if (Screen.orientation == ScreenOrientation.LandscapeLeft || Screen.orientation == ScreenOrientation.Landscape) return Quaternion.Euler(0, 0, -90); if (Screen.orientation == ScreenOrientation.LandscapeRight) return Quaternion.Euler(0, 0, 90); if (Screen.orientation == ScreenOrientation.PortraitUpsideDown) return Quaternion.Euler(0, 0, 180); return Quaternion.identity; }
And below here is the updated function to calculate camera rotation:
transform.rotation = ConvertRotation(Input.gyro.attitude) * GetRotFix();
The controller should update camera rotation referenced to the base device rotation and reset base camera rotation in the horizontal plane. It means that if user starts the application pointing the device to the north, the game camera will not rotate to the virtual north. The camera will show the given direction. Below is the new function that takes into account camera base rotation and device base rotation.
transform.rotation = cameraBase * ( ConvertRotation(referenceRotation * Input.gyro.attitude) * GetRotFix();
Calculation of the cameraBase and referanceRotation is a bit tricky. The main two obstacles are:
- You must take into account the current device orientation while calculating referenceRotation
- You must take into account only the rotation around up axis while calculating cameraBase
The exact functions you can find in the attached example.
And the final thing, smoothing camera rotation:
transform.rotation = Quaternion.Slerp(transform.rotation, cameraBase * ( ConvertRotation(referanceRotation * Input.gyro.attitude) * GetRotFix()), lowPassFilterFactor);
Now let’s add two functions AttachGyro and DetachGyro. The first one will enable the controller and recalculate all base rotations and the second one will disable the controller.
Finally our controller is ready. Please find the working example in the attachment. I will appreciate your comments and questions below. Hope, you will find this post useful!
Download example here
Author Alexander Dezhurko
Chief Technical Officer with Heyworks Unity Studio
Nice stuff!
helpful,thanks!
You are welcome!
Hi there,
thanks a lot for this article!
I am prototyping with Razer Edge Pro Tablet (Win 8.1) and have tested this example as winRT (Windows Store) App. When I move the tablet around (pitch, yaw, roll), I get some movements, but it seems that Pitch/Yaw/Roll are all swapped/inverted somehow – definitely not like a “window to the 3d world”. Are you interested in helping me to get it work on windows?
Josh
Hi Josh,
Sorry for the delay with reply. Please reach me by a.klimovich@heyworks.com, so we can discuss your issue in more details. Let’s see what we can help you with.
Andrei
Looks nice, will test it..hope it works!!
cheers!!
You are welcome!
Hi.
This is very cool.
Did you tested it with Android? I can’t get it to work with it, any thoughts on why it wouldn’t work?
It’s not working on my first generation Nexus 7, but i’ve tried on an old Samsung Galaxy S i9000 and it works.
So i guess the problem is not with Android, but probably tied to hardware.
I’ve discovered that it works fine also on the Nexus 7.
For some reason on Android the gyro starts deactivated, so clicking on “On/Off gyro” is required to see the scene.
Nice! I’m glad that you solve this issue
Dear Alexander,
Thank you for the great job and for sharing it.
It works fine on my Nexus 7.
Keep sharing.