Home > Back-end >  Unity: Rotation of an Object is not working correctly
Unity: Rotation of an Object is not working correctly

Time:08-22

I am trying to rotate the light source of my Scene on one Axis with this code:

IEnumerator SunMoving()
{
    while (true)
    {
        Quaternion fromAngle = transform.rotation;
        Quaternion toAngle = Quaternion.Euler(transform.eulerAngles   (Vector3.left * dayRotation));

        for(float t = 0f;  t < 1; t  = Time.deltaTime)
        {
            transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
            yield return null;
        }
    }
}

void Start()
{
    dayRotation = 360 / daySeconds;
    //nightRotation = 180 / nightSeconds;
    StartCoroutine(SunMoving());
}

But it is not working correctly. I am really new to quaternions and rotation in general, so any help is appreciated.

Thanks in advance and sorry for my bad english :)

CodePudding user response:

You should use the update function instead of the start function to rotate stuff. Secondly quaternions have an extra dimension w which needs to be computed. A difficult aspect of quaternions is that the order of operation matters a lot. -> transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t); not sure about this line.

CodePudding user response:

If you want to animate a sun object (directional light) you don't lerp between two different rotations but calculate angles from a formula that approximates this continuous motion

sun light controller

using UnityEngine;

public class SunController : MonoBehaviour
{
    [SerializeField][Range(0,1)] float _dayTime = 0.5f;// 0.5 means noon
    [SerializeField] float _timeScale = 1;

    [SerializeField] Light _sun = null;
    [SerializeField] Vector2 _sunAtMidnight = new Vector2(45,0);// degrees
    [SerializeField] Vector2 _earthAxis = new Vector2(-45,0);// degrees
    const float degreesPerSecond = 360f / secondsPerDay;
    const float secondsPerDay = 24*60*60;// seconds per day
    [SerializeField] AnimationCurve _sunIntensity = new AnimationCurve(
        new Keyframe(0,0) ,
        new Keyframe(0.25f,0) ,
        new Keyframe(0.5f,1) ,
        new Keyframe(0.75f,0) ,
        new Keyframe(1,0)
    );
    [SerializeField] Gradient _sunColor = new Gradient{ colorKeys=new GradientColorKey[]{
        new GradientColorKey(new Color(1,0.3f,0,1),0) ,
        new GradientColorKey(Color.white,0.5f) ,
        new GradientColorKey(new Color(1,0.3f,0,1),1)
    } };

#if UNITY_EDITOR
    void OnValidate ()
    {
        if( _sun!=null && _sun.type==LightType.Directional ) _sun.type = LightType.Directional;
    }
#endif

    void FixedUpdate ()
    {
        // step simulation time:
        _dayTime = ( _dayTime   ( Time.fixedDeltaTime * _timeScale ) / secondsPerDay ) % 1f;
    }
    
    void Update()
    {
        Vector3 sunPositionNow = SunPositionAtTime(_dayTime);
        _sun.transform.rotation = Quaternion.LookRotation( -sunPositionNow );
        _sun.intensity = _sunIntensity.Evaluate(_dayTime);
        _sun.color = _sunColor.Evaluate(_dayTime);
        _sun.enabled = _sun.intensity>0;
    }

#if UNITY_EDITOR
    void OnDrawGizmos ()
    {
        Vector3 position = transform.position;
        
        Gizmos.color = Color.cyan * 0.3f;
        Gizmos.DrawRay( position , Quaternion.Euler((Vector3)_earthAxis) * Vector3.forward );
        
        Gizmos.color = Color.black;
        Gizmos.DrawRay( position , Quaternion.Euler((Vector3)_sunAtMidnight) * Vector3.forward );

        if( Application.isPlaying )
        {
            Gizmos.color = Color.white;
            Gizmos.DrawRay( position , SunPositionAtTime(_dayTime) );
        }
        
        int numSteps = 100;
        for( int i=0 ; i<=numSteps ; i   )
        {
            float t = (float)i / (float)numSteps;
            Gizmos.color = _sunColor.Evaluate(t) * new Color(1,1,1,Mathf.Max(_sunIntensity.Evaluate(t),0.05f));
            Gizmos.DrawRay( position , SunPositionAtTime(t) );
        }
        
        Gizmos.color = Color.yellow * 0.3f;
        Gizmos.DrawWireSphere( position , 1f );
        
        int dayTimeSeconds = (int)(_dayTime * secondsPerDay);
        int h = dayTimeSeconds/(60*60);
        int m = (dayTimeSeconds%(60*60))/60;
        int s = dayTimeSeconds`;
        UnityEditor.Handles.color = Color.red;
        UnityEditor.Handles.Label( position , $"time of day: {h:00.}:{m:00.}:{s:00.}" );
    }
#endif

    // t is 0-1 range
    Vector3 SunPositionAtTime ( float t )
    {
        Vector3 midnightDir = Quaternion.Euler((Vector3)_sunAtMidnight) * Vector3.forward;
        Vector3 earthAxisDir = Quaternion.Euler((Vector3)_earthAxis) * Vector3.forward;
        return Quaternion.AngleAxis( t*secondsPerDay*degreesPerSecond , earthAxisDir ) * midnightDir;
    }

}
  • Related