How to rotate an object along all 3 axes with finger swipe?

Viewed 1607

I'm working on a simple AR Vuforia application. How can I implement the rotation of an object along all three axes with one finger swipe?

The code I'm currently using has one bug: the rotation of the object depends on its local axes. For example, if I look at the object from the front, everything works as it should, but if I look at the object from the back side, the finger swipe upwards makes it rotate downwards and vice versa.

Here is this script:

public float rotSpeed = 30f;

void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X")*rotSpeed*Mathf.Deg2Rad;
float rotY = Input.GetAxis("Mouse Y")*rotSpeed*Mathf.Deg2Rad;

transform.Rotate(Vector3.up, -rotX);
transform.Rotate(Vector3.right, -rotY);
} 

This is not what I need, how can I rotate the object according to the finger swipe direction regardless of the angle from which I look at it?

Update

A simple non-AR example, which may help you understand what I need is an iOS game "Space Frontier 2". After a successful launch of the rocket, it lands on the planet and you can rotate the planet with your finger swipe.

Here is the video demo: https://youtu.be/OiNPP1WNIAI

3 Answers

This works nice regardless of your object's rotation, and regardless of your camera position relative to the object:

public float rotSpeed = 30f;

void OnMouseDrag()
{
    float rotX = Input.GetAxis("Mouse X") * rotSpeed;
    float rotY = Input.GetAxis("Mouse Y") * rotSpeed;

    Camera camera = Camera.main;

    Vector3 right = Vector3.Cross(camera.transform.up, transform.position - camera.transform.position);
    Vector3 up = Vector3.Cross(transform.position - camera.transform.position, right);

    transform.rotation = Quaternion.AngleAxis(-rotX, up) * transform.rotation;
    transform.rotation = Quaternion.AngleAxis(rotY, right) * transform.rotation;
}

Make sure your camera has the "MainCamera" tag, or assign the camera externally if necessary.

I do not have the exact code with me right now.

But if you did not update your point of view coordinates, this should be the expected result.

Consider a real ball with 2 colors, blue and red, separated vertically. When you are in front of it, seeing only the blue side, stroking it up will make the blue side go up and the red side appear from the bottom. Now move behind it, seeing only the red side, and stroke it up again. The blue face will go down and appear from the bottom. Unity applies physics to virtual objects the same way we interact with real objects.

So you need to consider your camera position with the object orientation when you apply movements to it. You need to apply a transformation matrix to your movement based on your camera location related to the object origin orientation.

I hope this is clear enough to put you on tracks to fix it.

I think you have to somehow clamp the rotation to have the desired behaviour. I wrote a script recently to do just that. I did a little modification though.

public float rotSpeed = 30f;

float ClampAngle(float _angle, float _min, float _max)
{
    if (_angle < 0f) _angle = 360 + _angle;
    if (_angle > 180f) Mathf.Max(_angle, 360 + _min);
    return Mathf.Min(_angle, _max);
}

USAGE:

void RotateGameObject()
{
    float h = Input.GetTouch(0).deltaPosition.x * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
    float v = Input.GetTouch(0).deltaPosition.y * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;

    Vector3 rot = transform.rotation.eulerAngles + new Vector3(-v, h, 0f);
    //Change the y & z values to match your expected behaviour.
    rot.x = ClampAngle(rot.x, -5f, 20f);
    //Clamp rotation on the y-axis
    rot.y = ClampAngle(rot.y, -20f, 20f);
    transform.eulerAngles = rot;
}

See if that works and of course, try to play with the values.

Related