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
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;
}
}