Rotate object to its nearest "side".

Hey all. The premise is simple: I want to adjust the X rotation of my 3D Cube to its nearest side through interpolation. So if I my cube’s X rotation is greater than 0 but lesser than 45 I want it to rotate to 0, if it is greater than 45 but lesser than 90 I want it to rotate to 90, if >90 && <135 = 90, if >135 && <180 = 180, and so on to cover all the rotation, to keep the object always in one if its sides

I’m currently using Itween to sort of “achieve this thing” (in a very buggy way). I’m using the code from below, but is not correctly working:

if(body.transform.rotation.x > 0 && body.transform.rotation.x < 46)
            {
            iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 0, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 45 && body.transform.rotation.x < 91)
            {
                iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 90, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 90 && body.transform.rotation.x < 136)
            {
                iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 90, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 135 && body.transform.rotation.x < 181)
            {
                iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 180, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 180 && body.transform.rotation.x < 226)
            {
                iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 180, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 225 && body.transform.rotation.x < 271)
            {    
                iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 270, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 270 && body.transform.rotation.x < 316)
            {
                iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 270, "speed", fixPlayerRotationSpeed));
            } else if (body.transform.rotation.x > 315 && body.transform.rotation.x < 361)
            {
             iTween.RotateTo (body, iTween.Hash ("name", "fixBodyRotation", "x", 359.99f, "speed", fixPlayerRotationSpeed));
            }

Anyone know a better way?

Would this answer help?

and maybe combine it with lerpAngles

Mmm thank you for your reply. I tried with the links you gave me, used this code

            float minAngle, angle;
            Vector3 maxAngle = new Vector3();
            maxAngle = body.transform.eulerAngles;
            maxAngle.x = Mathf.Round(maxAngle.x / 90) * 90;
            minAngle = body.transform.rotation.x;
            angle = Mathf.LerpAngle(minAngle,maxAngle.x,1f);
            body.transform.eulerAngles = new Vector3 (angle,0,0);

Idk if something is wrong, but it is not interpolating from A to B, also sometimes when it reaches 0 it’s doing a complete flip.

Maybe this will work

This is a simple version
Rotate All version

using UnityEngine;

public class RotateToNearestSide : MonoBehaviour
{
    public float speed = 5f;
   
    void Update()
    {
        transform.localEulerAngles = RotateAxisToNearestSide(transform.localEulerAngles);
    }
   
    Vector3 RotateAxisToNearestSide(Vector3 eulerAngles)
    {
        Vector3 roundedEulerAngles = RoundToNearest90Degree(eulerAngles);
        return Vector3.Slerp(eulerAngles, roundedEulerAngles, Time.deltaTime * speed);
    }
   
    Vector3 RoundToNearest90Degree(Vector3 eulerAngles)
    {
        for(int i = 0; i < 3; i++)
        {
            eulerAngles[i] = Mathf.Round(eulerAngles[i] / 90f) * 90f;
        }
        return eulerAngles;
    }
}

With this version, in the inspector you can set which axis you want it to rotate. So if you dont want it to rotate any axis other than x, you put 0 in the y and z.
Rotate SelectAxis version

using UnityEngine;

public class RotateToNearestSide : MonoBehaviour
{
    public Vector3 selectedAxis = Vector3.one;
    public float speed = 5;

    void Update()
    {
        transform.localEulerAngles = RotateAxisToNearestSide(transform.localEulerAngles, selectedAxis);
    }

    Vector3 RotateAxisToNearestSide(Vector3 eulerAngles, Vector3 selectedAxis)
    {
        Vector3 rounded = RoundToNearest90Degree(eulerAngles);
        Vector3 slerped = Vector3.Slerp(eulerAngles, rounded, Time.deltaTime * speed);
        return SetSelectedAxis(eulerAngles, slerped, selectedAxis);
    }

    Vector3 RoundToNearest90Degree(Vector3 eulerAngles)
    {
        for(int i = 0; i < 3; i++)
        {
            eulerAngles[i] = Mathf.Round(eulerAngles[i] / 90f) * 90f;
        }
        return eulerAngles;
    }

    Vector3 SetSelectedAxis(Vector3 original, Vector3 desired, Vector3 selectedAxis)
    {
        for(int i = 0; i < 3; i++)
        {
            if(selectedAxis[i] != 0)
            {
                selectedAxis[i] = desired[i];
            }else{
                selectedAxis[i] = original[i];
            }
        }

        return selectedAxis;
    }
}

I am using Time.deltaTime in the lerp, but ill send you here if you want to see different ways to handle lerp.

Thank you, your solution works like a charm.

1 Like