# How to get the angle of a directional light relative to the horizon?

I’m just struggling an exceptional amount with vectors and rotations in Unity when working in 3D. It’s embarrassing.

I have a directional light (my sun) which I rotate 360 degree around the x-axis to simulate a day night cycle. I want to get the rotation value which is shown if you manipulate the inspector manually. When you rotate something by code it seems to go to 90 degrees back to zero and then to negative zero instead of through the full 360. And it “sticks” to 90 degrees for a very long time and seemingly starts changing the other rotations instead if I watch the inspector why my day night cycle runs.

I want this:
0 degrees rotation = sunrise.
90 degrees = midday (the sun is in zenith)
180 degrees = sunset
270 degrees = midnight (the moon would be in zenith if I decided to add one)
360 degrees = 0 degrees (the next day starts)

I already have the functionality working, but I’m not working with rotations in degrees. I’m using dot products, float values between 0 and 1 and all sorts of messy stuff. I want to make the code easier for me to work with. I want it so that if I input a value of 5 degrees I know the sun has just risen or if I input a value of 175 degrees it’s about to set. What I have now is a mess.

No matter how I approach this I can’t seem to get the value I want back from Unity. I’ve always been brute forcing these sort of problems through trial and error because this whole thing just seems to be that much more confusing that it should be. It may be that I’m thinking of this in terms of 2D and it’s completely different in 3D or something, but I can’t wrap my head around why it is so hard.

For instance I have tried this:

``````print (Vector3.Angle(sun.transform.forward, Vector3.forward));
``````

Vector3.forward is the world space blue vector in the scene view right? And transform.forward is the local space blue vector of my game object. Why isn’t this giving me the correct angle?

Edit: Well, that was quick. It seems it helps to cry about it on the forums. I just realized that it works if I leave all the other rotations to 0, but when they are not zero (as was the case for me) I don’t get the pure x angle back, but the angle difference between all the axis. Which is pretty obvious, duh.

I guess I need to compare the sun angle to a target game object which is in the same local space as the sun.

Even though you found a solution, I just want to note that you don’t need to Vector3.Angle() to get a rotation value - just use transform.eulerAngles.x. You get the actual rotation value, instead of the 90 degree based one, which is caused by Vector3.Angle() always returning the smallest angle.

Thanks for the reply, but like I said transform.eulerAngles.x doesn’t return the correct angle. It goes from 0 to 90, then stays at 90 for a long time while the other axis suddenly start changing, then it goes from 90 back to 0 and then from 360 to 270 and back to 360. Not really usable in my opinion. No idea how I would convert that to a full 0 to 360 degree rotation like I want. And the part where it sticks to 90 degrees seems to suggest something is not right. Probably some gimbal lock issue or whatnot?

Oh, you didn’t explicitly mention that was the behaviour you were experiencing from transform.eulerAngles, which is why I mentioned it. It does indeed appear to be a gimball locking related issue, you can read about it in Bunny83’s comment in this question. I didn’t know about this either until now.

1 Like

I was messing around with something similar yesterday.

Heres teh code(just slam to directionlight):

``````using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class sunRotation : MonoBehaviour {
float timer;
public float smooth = 10;
public int nextDayTime = 0;
public List<Quaternion> dayTimes = new List<Quaternion>();
// Use this for initialization
void Start () {
Quaternion Morning  = Quaternion.Euler(45, 0, 0);
Quaternion Day  = Quaternion.Euler(90, 0, 0);
Quaternion Evening  = Quaternion.Euler(135, 0, 0);
Quaternion Night  = Quaternion.Euler(-78, 0, 0);
}

// Update is called once per frame
void Update () {
Quaternion target = dayTimes[nextDayTime];
transform.localRotation = Quaternion.Slerp (transform.rotation, target, Time.deltaTime * smooth);
if (Time.time > timer) {
letfRollTehSunHurrDurr();
}
}

void letfRollTehSunHurrDurr(){
if (nextDayTime < 3) {
nextDayTime += 1;
} else {

nextDayTime = 0;
}
Debug.Log (dayTimes[nextDayTime].ToString());
}
}
``````

Change addTimer to set seconds how long 1 daytime lasts and smooth to how fast daytime changes.

Thanks, Joac. I’ll check it out to see if there’s anything of interest for me in there, but I actually realized I had what I wanted in my code already, I was just too stupid to see it so I was looking for convoluted solutions instead.

This code was in there all along:

``````sun.rotation = Quaternion.Euler(currentTimeOfDay * 360, positionOnHorizon, 0);
``````

But I didn’t realize that actually gave me the angle I wanted all along so I tried calculating it for some reason. It happens so often for me that I sit there for hours trying to figure out something that was trivial to begin with. I need to step away from the code sometimes and come back later instead.

“letfRollTehSunHurrDurr”, nice method name.

I also realized that having the sun rise at 90 degrees and set at 270 is much easier to work with because I can fade it in/out between values like 88-92 and 268-272 instead of it switching from 360 to 0 right on the horizon. I made 0 degrees midnight instead. This more sense in terms of game time as well as that’s the actual start of a new day.

So all I had to do was change my code to:

``````float angle = currentTimeOfDay * 360;
sun.rotation = Quaternion.Euler(angle - 90, positionOnHorizon, 0);
``````

Which gives me the angle I need for the rest of the script and gives the sun game object the correct rotation.