Search Unity

Day and Night Cycle rotation Problem

Discussion in 'Scripting' started by PrieDayThor, Nov 12, 2015.

  1. PrieDayThor

    PrieDayThor

    Joined:
    Jun 18, 2015
    Posts:
    16
    Hey guys,

    I'm currently working on a day and night cycle for my project.
    The problem is that I get some weird angles after I try to rotate my light.
    Atm I calculate the passed seconds with the following formula:

    float alreadyPassedSeconds = ((System.DateTime.Now.Hour * 60 * 60) + (System.DateTime.Now.Minute * 60) + System.DateTime.Now.Second);

    After that I take that float and multiply it with the degrees per second:
    DEGREES_PER_SECOND = 360 / SECONDSOFADAY; // SECONDSOFADAY = 86400
    float startRotation = DEGREES_PER_SECOND * alreadyPassedSeconds;

    And after that I simply rotate my sun/light on the x-axis to that value:
    sun.transform.rotation = Quaternion.Euler(startRotation, 0, 0);

    After I started my program at Hour: 16 Minute: 43 Second: 22 I get the startrotation of 250.8417.
    So the values are fine but the rotation of the light is at 289.1565 and the scene is dark.

    Where is my misconception?

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DayAndNightCicleScript : MonoBehaviour {
    4.   public GameObject sun;
    5.  
    6.   private const float SECONDSOFADAY = 86400;
    7.   private const float SECOND = 1;
    8.   private const float MINUTE = 60 * SECOND;
    9.   private const float HOUR = 60 * MINUTE;
    10.   private const float DAY = 24 * HOUR;
    11.  
    12.   private const float DEGREES_PER_SECOND = 360 / SECONDSOFADAY;
    13.  
    14.   private float _SessionTime;
    15.  
    16.    // Use this for initialization
    17.    void Start () {
    18.   Debug.Log("Hour: " + System.DateTime.Now.Hour + " Minute: " + System.DateTime.Now.Minute + " Second: " + System.DateTime.Now.Second);
    19.   float alreadyPassedSeconds = ((System.DateTime.Now.Hour * 60 * 60) + (System.DateTime.Now.Minute * 60)  + System.DateTime.Now.Second);
    20.   float startRotation = DEGREES_PER_SECOND * alreadyPassedSeconds;
    21.   Debug.Log("StartRotation: " + startRotation);
    22.   sun.transform.rotation = Quaternion.Euler(startRotation, 0, 0);
    23.  
    24.   _SessionTime = 0;
    25.   }
    26.  
    27.   // Update is called once per frame
    28.   void Update() {
    29.   sun.transform.Rotate(new Vector3(DEGREES_PER_SECOND, 0, 0) * Time.deltaTime);
    30.   _SessionTime += Time.deltaTime;
    31.    }
    32. }
    33.  
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    7,195
    There seems to be a rash of issues with Euler angle lately. I never use them, myself, because they are sometimes counterintuitive. Try using Quaternion.AngleAxis instead. (Euler angles are just multiple AngleAxis calls really, only they don't always rotate quite intuitively. I find it more natural to call AngleAxis several times and * the results together.)

    (In particular, I can't help but notice the mathematical symmetry of your chosen test value and its result. 289.1565 ~= 540 - 250.8417. I'd bet good money that (actual result) = 540 - (expected result) holds true for at least that "quadrant" of rotation and probably beyond, and similarly patterned for other quadrants as well. That's basically an inversion as well as an "off by 180" error, both of which could be easily explained with unexpected Euler conversions.)

    I suspect that your problem in this case is more with the setup of your light object than the script.
     
  3. PrieDayThor

    PrieDayThor

    Joined:
    Jun 18, 2015
    Posts:
    16
    Hey,

    thanks for the answer.
    Now I tried:
    sun.transform.rotation = Quaternion.AngleAxis(startRotation, Vector3.right);

    But the result is the same. Hour: 12 Minute: 13 Second: 52 which would be an angle of 183.4667 somehow 'evolves' to 356.5318. I dont get it. My light is the standard light of a new generated scene but I think that none of it's options has something to do with the axis.. so what now?
    I honestly don't get it..
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    7,195
    Try using a different axis (like .left, maybe?)
     
  5. PrieDayThor

    PrieDayThor

    Joined:
    Jun 18, 2015
    Posts:
    16
    Doesn't work.
    I also tried adding or substracting of 180 but it also doesn't work.
    Tried something like this:

    Code (CSharp):
    1. int counter = (int)startRotation;
    2.         for(int i = 0; i < counter; i++)
    3.         {
    4.             sun.transform.Rotate(Vector3.right);
    5.         }
    still the same result.
     
  6. jmjd

    jmjd

    Joined:
    Nov 14, 2012
    Posts:
    45
    I think you need an offset that is the time of day when the sun object's rotation is zero. So in an empty scene, if I set the sun's rotation to zeros, then I see that the light's direction is heading down the z-axis. This roughly corresponds to 6 a.m. (If the light is pointing forward, it's dawn ~6 a.m., if it's straight down, it's noon, etc.)

    Here's the additions to your script to account for this, I added the START_OF_DAY_OFFSET on line 13, and I'm using it on line 23:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DayAndNightCicleScript : MonoBehaviour
    4. {
    5.     public GameObject sun;
    6.  
    7.     private const float SECONDSOFADAY = 86400f;
    8.     private const float SECOND = 1f;
    9.     private const float MINUTE = 60f * SECOND;
    10.     private const float HOUR = 60f * MINUTE;
    11.     private const float DAY = 24f * HOUR;
    12.  
    13.     private const float START_OF_DAY_OFFSET = 6f * HOUR;
    14.  
    15.     private const float DEGREES_PER_SECOND = 360f / SECONDSOFADAY;
    16.  
    17.     private float _SessionTime;
    18.  
    19.     // Use this for initialization
    20.     void Start()
    21.     {
    22.         Debug.Log("Hour: " + System.DateTime.Now.Hour + " Minute: " + System.DateTime.Now.Minute + " Second: " + System.DateTime.Now.Second);
    23.         float alreadyPassedSeconds = ((System.DateTime.Now.Hour * 60 * 60) + (System.DateTime.Now.Minute * 60)  + System.DateTime.Now.Second) - START_OF_DAY_OFFSET;
    24.         float startRotation = DEGREES_PER_SECOND * alreadyPassedSeconds;
    25.         Debug.Log("StartRotation: " + startRotation);
    26.         sun.transform.rotation = Quaternion.Euler(startRotation, 0, 0);
    27.  
    28.         _SessionTime = 0;
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update()
    33.     {
    34.         sun.transform.Rotate(new Vector3(DEGREES_PER_SECOND, 0, 0) * Time.deltaTime);
    35.         _SessionTime += Time.deltaTime;
    36.     }
    37. }
    38.  
    For me this seems to set the sun's direction at around the right time for me (16 hours, 22 minutes). Hope this helps!
     
  7. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,719
    you can always get the position like this:
    where center is de transform the script is on, and raduis the distance between your sun and the center
    Code (CSharp):
    1. Vector3 UpdatePosition()
    2.     {
    3.         Vector3 position;
    4.  
    5.         float angle = (360f/86400)*alreadyPassedSeconds;
    6.         float z = center.z+radius * Mathf.Sin(angle * Mathf.Deg2Rad);
    7.         float y = center.y+radius * Mathf.Cos(angle * Mathf.Deg2Rad);
    8.         position = new Vector3(center.x, y, z)+offset;
    9.         return position;
    10.     }
     
  8. PrieDayThor

    PrieDayThor

    Joined:
    Jun 18, 2015
    Posts:
    16
    Hey jmjd,

    I tried your code and it seems to work. Unfortunately in game mode the sun freezes at 90 degrees.
    Here is another thing. In editor mode I can rotate the light around the x axis freely. In game mode I can rotate between 90 - 360 - 270 degrees. Sometimes I can rotate after 270 degrees and sometimes not.
    That's all really weird...
     
  9. PrieDayThor

    PrieDayThor

    Joined:
    Jun 18, 2015
    Posts:
    16
    So Guys,

    since I can't get it to work I decided to cut this "feature". This is my code now:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class DayAndNightCicleScript : MonoBehaviour
    5. {
    6.   public GameObject sun;
    7.  
    8.   private const float MORNING = 30F;
    9.   private const float NOON = 90F;
    10.   private const float EVENING = 170F;
    11.  
    12.   private int lastHour;
    13.   private float _SessionTime;
    14.  
    15.   // Use this for initialization
    16.   void Start()
    17.   {
    18.   setSun(System.DateTime.Now.Hour);
    19.   _SessionTime = 0;
    20.   }
    21.  
    22.   // Update is called once per frame
    23.   void Update()
    24.   {
    25.   if(System.DateTime.Now.Hour != lastHour)
    26.   {
    27.   setSun(System.DateTime.Now.Hour);
    28.   }
    29.    
    30.   _SessionTime += Time.deltaTime;
    31.   }
    32.  
    33.   void setSun(int currentHour)
    34.   {
    35.   if (currentHour < 12 && currentHour > 6)
    36.   {
    37.   sun.transform.rotation = Quaternion.Euler(MORNING, 0, 0);
    38.   }
    39.   else if (currentHour < 18 && currentHour > 12)
    40.   {
    41.   sun.transform.rotation = Quaternion.Euler(NOON, 0, 0);
    42.   }
    43.   else if (currentHour < 24 && currentHour > 18)
    44.   {
    45.   sun.transform.rotation = Quaternion.Euler(EVENING, 0, 0);
    46.   }
    47.   else
    48.   {
    49.   sun.transform.rotation = Quaternion.Euler(360, 0, 0);
    50.   }
    51.  
    52.   lastHour = currentHour;
    53.   }
    54. }
    55.  
    56.  
    Had to get the values for the sun out of the game mode because there is a big difference between values of light in game and editor mode.
    I hope that someday someone can bring clarity to this matter.
     
  10. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,719
unityunity