March 9, 2015 | 34 comments

Simplest possible day night cycle in Unity 5

This is a quick tutorial on how to create the simplest possible day night cycle in Unity 5. Everything about it will be wrong compared to how it should be in real life, but chances are nobody will notice. And you can extend it with more features as you please.

Disclaimer: This is more of a "how I did it" rather than a fully fledged tutorial that you follow step by step. So If you're just interested in the end result scroll to the bottom to see an example webplayer or to download the project folder.

When you first start up Unity 5 chances are you have tried rotating the directional light that comes with the default starting scene. By doing that you've also probably noticed that the sun's position in the skybox as well as the color of the sky changes accordingly. So what I'm saying is that Unity 5 already does everything we need to create a day night cycle for us. All we need to do is control this rotation through a script.

Here's that script:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using UnityEngine;
using System.Collections;
 
public class DayNightController : MonoBehaviour {
 
    public Light sun;
    public float secondsInFullDay = 120f;
    [Range(0,1)]
    public float currentTimeOfDay = 0;
    [HideInInspector]
    public float timeMultiplier = 1f;
    
    float sunInitialIntensity;
    
    void Start() {
        sunInitialIntensity = sun.intensity;
    }
    
    void Update() {
        UpdateSun();
 
        currentTimeOfDay += (Time.deltaTime / secondsInFullDay) * timeMultiplier;
 
        if (currentTimeOfDay >= 1) {
            currentTimeOfDay = 0;
        }
    }
    
    void UpdateSun() {
        sun.transform.localRotation = Quaternion.Euler((currentTimeOfDay * 360f) - 90, 170, 0);
 
        float intensityMultiplier = 1;
        if (currentTimeOfDay <= 0.23f || currentTimeOfDay >= 0.75f) {
            intensityMultiplier = 0;
        }
        else if (currentTimeOfDay <= 0.25f) {
            intensityMultiplier = Mathf.Clamp01((currentTimeOfDay - 0.23f) * (1 / 0.02f));
        }
        else if (currentTimeOfDay >= 0.73f) {
            intensityMultiplier = Mathf.Clamp01(1 - ((currentTimeOfDay - 0.73f) * (1 / 0.02f)));
        }
 
        sun.intensity = sunInitialIntensity * intensityMultiplier;
    }
}
I removed all the comments so that the script doesn't take up so much space here, but it's fully commented in the project folder.

You attach this script to a game object in the scene and then assign your directional light in the sun slot. What this script does is increase a value from 0 to 1 over the number of seconds we specify. This value defines a full 24 hour in game day where 0 is midnight, 0,25 is sunrise, 0,5 is noon, 0,75 is sunset. By default a full day and night takes 120 seconds as you can see. When the value reaches 1 we reset it back to 0 so that the next day can start.

UpdateSun() is what actually moves the sun. To rotate the sun across the sky the only thing we need is the first line. We rotate the sun 360 degrees around the x-axis according to the current time of day. We subtract 90 degrees from this to make the sun rise at 0.25 instead of 0. I just found that value easier to work with. The y-axis determines where on the horizon the sun will rise and set. I set this to 170 because it fit my test scene. The z-axis rotation does nothing here.

The rest of the UpdateSun() mehtod only deals with the intensity of our sun. We want the intensity of the sun to be 0 when it's below the horizon so it doesn't shine up from below the ground because that looks really weird. And I've also added some code to fade in the intensity when the sun rises and fade out the intensity when the sun sets. That's all there is to it.

But if you try this out now and you have some objects in your scene you will notice that the objects stays lit even during the night, even if you mark them as static. That is not what we want. To fix this there's 2 things you must do. The first is to add a "Reflection Probe" to the scene and set its type to "Realtime" and set the refresh mode to "Every frame":

Reflection Probe settings
The rest of the settings doesn't matter. "Time slicing" is just a performance setting.

Now any static geometry you add to the scene will be properly lit, but dynamic objects still won't receive the correct lighting. But we can fix this as well. Add a "Light Probe Group" to the scene. You don't have to change any settings for this to work. It works automatically. Now even dynamic objects will be properly lit by your dynamic sun.

You may have to tweak the settings and positions of your probes to make everything look perfect. But all that depends on your scene setup. I have added links to the official documentation entries for reflection probes and light probes to the bottom of this tutorial. There's a lot of information there if you stumble upon some problems. Or just ask me.

That's it, we're done now with the day night cycle now. But you probably noticed the clock in the image at the top of this tutorial. I added that because I thought it would be cool to actually see the current time of our day night cycle as time passes. I'll show you how I made it. It's all included in the project folder as well. The clock is based on this tutorial by Jasper Flick. He makes amazing Unity tutorials. Much more elaborate than this one. All I do is steal his stuff.

But anyway, the clock is just an object resembling a clock with another simple script attached. You can, and probably should, make the clock object as a 3d model in a modeling application, but I made it in Unity for this tutorial by just sticking a bunch of cube and cylinder primitives together. The only important parts of the clock object are the hands indicating the current hour and the current minute. We need to be able to reference them through script and they should be able to rotate 360 degrees around on a pivot in the center of the clock face. As for the clock script, here it is:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using UnityEngine;
 
public class Clock : MonoBehaviour {
    
    public Transform hourHand;
    public Transform minuteHand;
    
    float hoursToDegrees = 360f / 12f;
    float minutesToDegrees = 360f / 60f;
    DayNightController controller;
    
    void Awake() {
        controller = GameObject.Find("DayNightController").GetComponent<DayNightController>();
    }
    
    void Update() {
        float currentHour = 24 * controller.currentTimeOfDay;
        float currentMinute = 60 * (currentHour - Mathf.Floor(currentHour));
        
        hourHand.localRotation = Quaternion.Euler(currentHour * hoursToDegrees, 0, 0);
        minuteHand.localRotation = Quaternion.Euler(currentMinute * minutesToDegrees, 0, 0);
    }
}
The clock script takes the currentTimeOfDay variable from our DayNightController and converts it to hours and minutes so that we can move the hands of the clock face accordingly.

It's really simple. First we define how many hours there are per day and how many minutes there are per hour. Then we define how many degrees each hour should be on our clock face and how many degrees each minute is. In Update() we get the currentTimeOfDay variable (which is a float between 0 and 1) from the DayNightController and multiply that with the values we've defined to get the current hour and the current minute. We then rotate the hour hand and the minute hand of the clock face according to these values. Obviously we could do seconds here as well, but they would pass so rapidly I chose not to. Again this script is fully commented in the project.

And that's everything, or nearly everything. If you read through the DayNightController script you may have noticed the public timeMultiplier variable. That is there so other scripts can change how fast the day night cycle passes. I have added a small script to my scene which lets me speed up or slow down time using W, S or arrow up or arrow down. It's fully commented in the project folder. I also added Bloom to make it look Next-GenTM and I added a bunch of rigidbody spheres to show you that it works perfectly with dynamic moving objects. The emissive parts of the clock also show you how amazingly cool the real time global illumination in Unity 5 is.

Ways to improve this effect would be to make the sun actually move more realistically across the sky and not just directly across it, to make it so you can have longer days/nights, or to add a starry sky or even a moon. The sky's the limit.

Check out an example webplayer here:
/projects/unity-5-day-night-cycle-example-scene

Or download the entire project folder here if you want to have a look:
/sites/default/files/unity/project/day-night-cycle-1.0.1.zip

Here's the official documentation entry about Reflection Probes:
https://docs.unity3d.com/Manual/class-ReflectionProbe.html

Read about Light Probe Groups and Light Probes here:
https://docs.unity3d.com/Manual/class-LightProbeGroup.html

Øyvind Strømsvik's picture

About Øyvind Strømsvik (TwiiK)

I've been passionate about games all my life and started dabbling in game development about 15 years ago with BlitzBasic,... read more but I quickly lost interest and began doing 3d modeling instead. 3d modeling remained a hobby and I picked up game development again around the release of Unity 2.0. My driving force behind wanting to get back into game development was my lost interest in commercial games as they started appealing to a group of gamers I was no longer in. Indie games were the only games that still looked interesting, but at the same time some of them looked like they would be just as fun to make as to actually play. And many of them were made by just one guy.

Tagged with: 3D, Tutorial, Unity
Leo's picture

Leo

Hey!, simple but really good tutorial, i have two days trying to update my TimeOfDay script to Unity5 and was having that problem, i didnt had any idea u had you had to use the Probs.

I do have another question close to this, maybe you can make another quick tut, trying to implement this to a big scene , say 2Kx2k map with mountains ? , would i have to do something different to get the TOD to work correctly?

Thanks and keep it comming!

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Leo: I'm not sure. I have never really tried making big maps in Unity. By 2k x 2k map you mean terrain, right? Have you tried it and it didn't work?

Leo's picture

Leo

@TwiiK: Yeah i mean the terrain size, but well to fix the proper lighting you use a reflection probe and a reflection group, if i have a huge map that means i have to add tons of reflection probes? i see the probe has like a range could that make the difference?, am actually using only diffuses and lowpoly geometry light, so i kindda dont need all the reflectivity of the PBR shaders, but i find that Unity5 light dosnt like at all my project not using pbr or diffuse/normal maps... it just look not that good as it was on u4

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Leo: Hmm, yeah. I see your point. I was going to revise the tutorial a bit adding a section about why you need the probes and what they do, but I'm actually not sure what the reflection probe does in terms of lighting. It's obviously something to do with the ambient lighting, but I'm not sure exactly what. I will have to read up on that or experiment a bit.

As for the light probes you should check out the Viking Village demo on the asset store. It's a pretty big scene and they've practically filled it with light probes. I'm actually not sure what you're expected to do in terms on MMO-scale maps. If you're meant to place thousands of probes or if there are better ways.

Anyway, I think you'll have more luck asking these questions on the Unity forums. I may test this out some later today to see if I can find some immediate answers, but don't count on it. :)

Arav Singhal's picture

Arav Singhal

It's great to see the graphics capabilities of Unity 5. I always loved Unity, its small learning curve and organized component system and of course the Asset Store. ;) With Realtime GI and PBR, it is pretty easy to make AAA looking games even for mobile. Although I would like it even more if a completely realtime system of GI would be implemented (i.e. with support for dynamic objects thus without precomputation. Maybe a mixture of that like precomputed GI for static objects and realtime GI for dynamic objects, but of lower quality (so that a reasonable rate of FPS can be maintained). The problem is right now dynamic objects can only receive realtime GI through light probes and not contribute to it.

Finn Fallowfield's picture

Finn Fallowfield

Thank you so much for your tutorials - I am making an iOS survival horde game with infinite waves of enemies a little similar to the Unity example project but massively extended and your tutorials have helped so much! I am trying to do random map generation but will probably end up just making a few simple maps myself. Thanks again for your awesome tutorials - please keep making them :D.

Ali Nagori's picture

Ali Nagori

thanks it's was very helpful.

Mitchel's picture

Mitchel

Great tutorial it's been rather helpful. I, however have ran into the problem on which Unity will spit out a CS0236 on line 13 in the controller code. Have you or any one else had a similar problem with that little bit of code? Any possible way around that?

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Mitchel: I googled CS0236 and it says "field initializer cannot reference a nonestatic field, method or property". As far as I know that's the type of error you get if you try to use GetComponent on a public variable or initialize an array directly on a public variable. I don't see how you can get that from line 13 or anywhere in that script. Line 13 is a comment even in the commented version. In the uncommented version it's just a public float.

My guess is that you're copy/pasting the script by hand and have made a typo? Can I ask that you download the project directly and compare it to your version?
http://twiik.net/sites/default/files/unity/project/day-night-cycle-1.0.1...

If this doesn't help feel free to contact me directly:
http://twiik.net/contact

Connor Schilling's picture

Connor Schilling

This day night/ cycle is great, but is there a way to get a color gradient to progress throughout the day? For example, the early morning and evening being a saturated orange, mid day being a desaturated yellow, and night being a dark blue/ black? I'm a novice in any of this, and have just started figuring out C#, so any help would be appreciated.

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Connor Schilling: It's not that hard actually. I have something like that in my arch viz project. My plan is to upload the project folder for that project when I'm done with it, and perhaps expand this tutorial when that is done.

I can't give you a time estimate for when that will be though. I have no idea. At least a month I reckon.

Sorry for the late reply btw. I've been away for a month.

Tobias's picture

Tobias

Quick question. I tried figuring this out but just broke the system instead. Would it be possible for the slider to go between 0-24 instead of 0-1? And somehow have the rest change depending on that. Then I would be easier for a level designer to set the time as it would be based on a 24 hour clock instead of %. :)

(Sorry if this is a super easy solution, just couldn't figure it out)

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Tobias: Just set the range to 0,24 instead and divide it by 24 in the script?

Cetaceo's picture

Cetaceo

@Connor Schilling: If someone like me come to see this awesome tutorial and have the same question, here's my solution:
Set the currentTimeOfDay range to 0, 24
replace that in your script:

currentTimeOfDay += ((Time.deltaTime * 24f) / secondsInFullDay) * timeMultiplier;

if (currentTimeOfDay >= 24)
{
currentTimeOfDay = 0;
}

And chage the sun rotation to this:

sun.transform.localRotation = Quaternion.Euler((currentTimeOfDay * 15f) - 90, -30, 0);

works for me.

cetaceo's picture

cetaceo

@Tobias: Forgot, you need to rework in intensityMultiplier of your sun, or it be dark all the time!

Mike's picture

Mike

Hey there, great script :D

If I wanted the cycle to only start after a keypress how would you go about this? Again thank you!

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Mike: Just add a variable like:

bool runCycle = false;

and in the Update() method add something like this to the beginning:

if (Input.GetKeyDown("space")) {
runCycle = !runCycle;
}

if (!runCycle) {
return;
}

That way it won't run the rest of the code unless space is pressed. And if you press it again you stop the cycle.

I can't test this for you or provide examples because I'm very busy with other things at the moment, I'm sorry.

Alvarz's picture

Alvarz

Nice tutorial it's really help me. I have a question, with this :
float currentHour = 24 * controller.currentTimeOfDay;
float currentMinute = 60 * (currentHour - Mathf.Floor(currentHour));
we can calculate minutes and hour, from that, how can I know how many days, months and years have been passed?

Caleb harwell's picture

Caleb harwell

I have this done..btw great day night, but i added a bunch of rocks to my scene and they are still lit during the night
How do i fix this?..

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Caleb harwell: I'm guessing it's one of three things:

a) You've forgotten to enable "Use Light Probes" for the rocks. It's a setting in the Mesh Renderer component.

b) You've forgotten to add light probes all together.

c) You're using a weird material/shader for the rocks. One that is unlit perhaps?

Calis's picture

Calis

Very well done my friend! I have one question; How do I make the day start in the morning instead of night? I tried everything. Thanks!

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Calis: You have to fiddle with the if-statements in the UpdateSun() method and on the first line of that method where I rotate the sun you have to change the - 90 part to either 0 or to + 90, I guess.

MG's picture

MG

Sorry for pulling this one from the nether, but I'm having some issues.
I've implemented it as described, but when it becomes night the shapes don't really get obscured like in real darkness. The Web player example works fine, but when I download the project files and run them locally, it also doesn't look right. The items in my scene just kind of...become grey, I suppose, and I can see them all perfectly still. Obviously not ideal.

Is there some kind of setting inside Unity to fix this?

Øyvind Strømsvik's picture

Øyvind Strømsvik

@MG: What version of Unity do you have? It may have changed in newer version of Unity.

By the way there's a much more complex, but very usable day night cycle in the Courtyard project as well: https://assetstore.unity.com/packages/essentials/tutorial-projects/the-c...

MG Potgieter's picture

MG Potgieter

@Øyvind Strømsvik:

I'm on Unity 5.0.2f. Not sure where that version fits in the grand scheme of things. I'll also definitely check out the link you sent, thanks!

Spencer White's picture

Spencer White

When The time is night time, the scene is completely black. Is there a way to fix this?

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Spencer White: Hmm, there's probably plenty of ways. You can maybe add a directional light opposite of the sun and set as the moon, and then turn that light on/off depending on the time of day. Or you can play with the ambient lighting.

You can also check out the official Courtyard project on the Unity Asset Store. It has a much more complex day night cycle.

PS: Sorry for the late reply.

Spencer White's picture

Spencer White

@Øyvind Strømsvik: Wow, that looks like an amazing asset. Thanks for the recommendation!

chris's picture

chris

I'm currently working on an indie fighting game and I'm going to try this out today. how bad does it affect performance.

Øyvind Strømsvik's picture

Øyvind Strømsvik

@chris: With realtime global illumination and a realtime reflection probe the performance impact is probably going to be pretty noticeable, but it depends entirely on the rest of your game.

And there's surely more optimized settings you can use as well. Try it out and see, I guess. :p

Guilherme's picture

Guilherme

I tried to download the project zip file today and it says that the file is no longer available.
Could you please check if the link is still ok.
Thank you for the help!

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Guilherme: Ahh, frack. Thanks for telling me. I've updated all my projects, but forgot I had hardcoded some links into the articles etc.

Here's the correct link: http://twiik.net/sites/default/files/unity/project/day-night-cycle-1.0.1...

Alex's picture

Alex

Thank you for this, I have just implemented it into a game I am working on.

Syafiq's picture

Syafiq

hello, thank you for your great tutorial. Do you have tutorial for "working hours calculation"? For example, i need to calculate my total working hours in 5 days and make sure it has past 45 working hours. For example, on Monday I thumb-In at 7:00am and thumb-Out at 5:00. I need a calculation script to calculate how many hours I've worked during that day, including whole 5 days.

Thank you

Add new comment