- Home /
Rotate gyroscope-based camera over it's Y axis by swiping
Hello everyone,
Im trying to rotate the camera based on a user's swipe, normally it would be quite simple(yRotation=xSwipe) but my camera is based on the gyroscope which causes the game-world to stay straight relative to the real world no matter what the device orientation is. When swiping, I only want to rotate the camera over it's Y axis so the world still stays straight no matter how you swipe.
The gyroscope based camera already works but the swiping part does not. The problem is that the concept of "horizontal swipe" can be on both/either the X and/or Y axis on the screen.
The orientation Unity player setting is set to landscape so if you hold your device like the bottom phone of the image, a horizontal swipe would be on the screen-space X axis, if you hold your device like the top-left phone, a horizontal swipe would be on the screen-space Y axis, and if you hold your phone like the top-right phone, a horizontal swipe would be on both the screen-space X and Y axis, and if you hold your phone upside down, a horizontal swipe would even be on the negative-y axis.
I have tried, sketched and visualized a lot of situations but I can not come up with a way that works mathematically to allow this rotation by swiping, perhaps it's my lack of knowledge of quaternions or vector arithmetic or simply the limits of my imagination.
The properties I can work with are the swipe vector(x & y distance in pixels within a frame), the camera rotation which could be used as both a Quaternion or Euler angle and the camera up-vector. However I do not know how to convert/superimpose this X and Y movement in a way that considers the "up" of the camera.
Can someone help me out? Anything helps!
Use world coordinates ins$$anonymous$$d of screen? One way to accomplish this would be adding new invisible collider that is ignored by everything else except raycasting and which follows camera and covers whole screen, but doesn't rotate when camera does (like the world). Then raycast at the beginning of the touch, save that position and then when touch ends (swipe ends) get new position.
I could place a stationary sphere around the camera and track the touch positions and after that angles between touches... How can I use those to rotate the camera around it's Y axis? $$anonymous$$aybe by checking only the difference in angles about it's Y axis. I'd have to try this out!
Answer by Cambesa · Feb 23, 2017 at 02:14 PM
I've partially solved it by placing a spherical mesh collider with normals aiming inwards around the camera and writing this code(still messy but I'll optimize it when it works):
void Update()
{
RaycastHit hit1, hit2;
Vector3 begin = Vector3.zero, end = Vector3.zero;
float angle1, angle2;
if(Input.GetMouseButtonDown(0))
{
//get initial
initialRay = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.Log("Started swiping");
}
if(Input.GetMouseButton(0))
{
//get current
updateRay = Camera.main.ScreenPointToRay(Input.mousePosition);
//rotate
Collider collider = GetComponentInParent<Collider>();
if(collider.Raycast(initialRay, out hit1, 2f))
{
begin = hit1.point;
}
if(collider.Raycast(updateRay, out hit2, 2f))
{
end = hit2.point;
}
angle1 = Mathf.Atan2(begin.z - transform.position.z, begin.x - transform.position.x) * Mathf.Rad2Deg;
angle2 = Mathf.Atan2(end.z - transform.position.z, end.x - transform.position.x) * Mathf.Rad2Deg;
transform.Rotate(transform.parent.up, angle2 - angle1, Space.World);
//reset initial
initialRay = updateRay;
}
if(Input.GetMouseButtonUp(0))
{
Debug.Log("Stopped swiping");
}
}
It works very good but there's only one problem left, when you click somewhere and move the mouse or your finger to a different location on your screen and stop moving there while holding your mouse or finger on the screen, the rotation shakes all the time between two positions, I would expect it to do nothing because the initial ray and update ray would be exactly the same but for some reason it shakes. I'll take a look at it and return when I find a fix.
Thanks
Found the solution!
initialRay = updateRay;
had to be
initialRay =Camera.main.ScreenPointToRay(Input.mousePosition);
because this calculation is done after rotating the camera so the update ray was actually an old version of what actually is the current ray.
He Hi, I'm in the same situation with swipe script attach to parent object and gyro script attach to child object. Now when child y-Axis is changed due to gyro and then i try to change the rotation using vertical swipe I'm not getting the vertical effect as child rotation is already effected due to gyro rotation. Any help is appreciated.
I haven't attempted the vertical swipe yet but perhaps it's possible with two of these spheres around the camera, one used for x-swipe and one used for y-swipe. I think the y-swipe sphere should be a child object of the x-swipe sphere
I'm not using any sphere or collider that part I'm totally understandable above if you can share some demo of what exactly you've achieved might be helpful.
Also You say you've not attempted the vertical swipe are you having the problem in horizontal swipe then cause horizontal swipe is working fine in my case and pretty simple too.
Answer by IgorAherne · Feb 24, 2017 at 01:14 AM
@Cambesa, your camera tilts, but screen's coordinate system stays fixed relative to the phone.
We need to make the coordinate system follow the tilt, not the phone.
//re-specify the coordinate of the touch as being relative to the center of the screen, not the bottom left corner of the phone.
Vector2 centerPos = Input.touch[0].position - new Vector2(Screen.width, Screen.height) *0.5f ;
Quaternion gyro_rot = Input.gyro.attitude;
//we are only interested in rotation around the phone's perpendicular axis, which "sticks-out"
//http://answers.unity3d.com/questions/434096/lock-rotation-of-gyroscope-controlled-camera-to-fo.html
Quaternion referenceRotation = Quaternion.identity;
Quaternion deviceRotation = DeviceRotation.Get();
Quaternion eliminationOfXY = Quaternion.Inverse(
Quaternion.FromToRotation(referenceRotation * Vector3.forward,
deviceRotation * Vector3.forward)
);
Quaternion rotationZ = eliminationOfXY * deviceRotation;
Vector2 rotatedTouchPos = rotationZ * centerPos;
I think this should work. If not try:
Quaternion.Inverse(rotationZ) * centerPos;
Thanks for your reply
//we are only interested in rotation around the phone's perpendicular axis, which "sticks-out"
We are not exactly interested in the phones perpendicular axis, that was the first way I tried but it didn't work for sideways rotated phones like the top left and right image from the main post. We are actually interested in the rotation around the world up axis, it was solved with raycasts ins$$anonymous$$d of mathematically.
Your answer
Follow this Question
Related Questions
Gyroscope smooth transitions (minimizing jerk from tiny movements) 1 Answer
3D camera relatively using gyro a la N.O.V.A. 2 0 Answers
Gyroscope added rotation 0 Answers
How to set child position and rotation fixed respect parent? 0 Answers
Why the control with gyroscope inverted when I make 180 degrees turn? 1 Answer