OpenGL 3D Game Tutorial 28: Day/Night


LWJGL tutorial series on how to create a 3D Java game with OpenGL!

More skybox work this week, as we implement a day/night cycle.

Skybox Night Textures:

Day/Night System Example Code:

Support the series on Patreon:

Facebook Page:
Check out my game on IndieDB:

End of video music- Kai Engel, “Waking Stars”:


Xem thêm bài viết khác:


  1. For changing the fog brightness in the SkyboxShader, I used the following two lines in my render method, after loading the view matrix:

    float fogBrightness = (float)Math.pow( Math.sin( (24000f – time) / 24000 * Math.PI ), 5);
    //you can change this 5, it's essentially a gradient on how quickly you want the fog to start to brighten
    shader.loadFogColor(r * fogBrightness, g * fogBrightness, b * fogBrightness);

    I also made the appropriate changes to the day cycle, to make it more smooth and to cooperate with my brightness.

    private void bindTextures() {

    if (useDayCycle) {

    time += (DisplayManager.getFrameTimeSeconds() * 1000) / gameTimeRatio;


    time %= 24000;

    int texture1;

    int texture2;

    float blendFactor;

    //blend buffers: (0-5000, 5000-8000, 8000-16000, 16000-19000, 19000-24000)

    if(time >= 0 && time < 5000) {

    texture1 = nightTexture;

    texture2 = nightTexture;

    blendFactor = (time – 0)/(5000 – 0);

    } else if(time >= 5000 && time < 8000) {

    texture1 = nightTexture;

    texture2 = texture;

    blendFactor = (time – 5000)/(8000 – 5000);

    } else if(time >= 8000 && time < 16000) {

    texture1 = texture;

    texture2 = texture;

    blendFactor = (time – 8000)/(16000 – 8000);

    } else if (time >= 16000 && time < 19000) {

    texture1 = texture;

    texture2 = nightTexture;

    blendFactor = (time – 16000)/(19000 – 16000);

    } else {

    texture1 = nightTexture;

    texture2 = nightTexture;

    blendFactor = (time – 19000)/(24000 – 19000);



    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture1);


    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture2);



  2. Nice! Verry good as ever (and I know, 5 years later). But nobody noticed that the Stars gone with the wind as well as the clouds, same velocity? 😀 How can that change, so the rotation ist stopped for the nightTexture?…. ok…. I think I can solve that later by myself…. first I want to finish all the tutorials….

  3. I really like these tutorials, but for some reason, the night skybox doesn't work. I have been trying for over one hour to make this work and I still only know, that, as long as I use the day files everything works and as soon as i use the night files, everything turns black. Well, i guess i also know that the problem is somehow with these files, as i don't have a problem with the samplerCube and with switching the sampler cubes

  4. Can anyone help, In the video "time" is a float, and "time%=24000;" is used to reset time when it reaches 24000, but for C++ this dose not work, you cannot use % on floats, only int's, but using int's for all these calculations break the blending between textures. Is there an alternative for C++?

  5. anyone else just getting the night texture constantly? no change between the two? in the function provided in description, whatever I put in the first if statement (nightTexture/Texture) is what the sky box will stay as, no change, so its like after this first if statement something is not working. Can any one help?

  6. Why don't you end up with a night texture after ten frames if you start with blendFactor = 0 and do blendFactor += 0.1f at the end of bindAttributes()?

  7. I know I'm writing a bit late, but I started watching this TUT this month.
    Anyways, I think that I did something wrond while watching, and because I'm not sure I just wanted to ask: Is the fog rendering wrong or is it looking strange for me?
    (I dont mean the red lines, I did them to show what I mean with the fog!) Image with SkyBox Rendering: | Image without SkyBox:
    Thanks for helping!

  8. Instead of a fixed ambient and fog brightness, I made some modifications so that they're automatically adjusted according to the Sun's average brightness.


  9. I'm trying to linearly change the color of a light. Can anyone tell me what is wrong with this code?

    public static void changeColor(Vector3f color, int seconds)
    seconds *= 120;

    boolean xPositive = color.x > sun.getColor().x;
    boolean yPositive = color.y > sun.getColor().y;
    boolean zPositive = color.z > sun.getColor().z;

    float xChange = Math.abs(sun.getColor().x – color.x);
    float yChange = Math.abs(sun.getColor().y – color.y);
    float zChange = Math.abs(sun.getColor().z – color.z);

    float xChangeLinear = xChange / seconds;
    float yChangeLinear = yChange / seconds;
    float zChangeLinear = zChange / seconds;

    float xChangeFinal = xPositive ? xChangeLinear : -xChangeLinear;
    float yChangeFinal = yPositive ? yChangeLinear : -yChangeLinear;
    float zChangeFinal = zPositive ? zChangeLinear : -zChangeLinear;

    Vector3f finalColor = sun.getColor();

    for (int i = 0; i < seconds; i++)
    finalColor.x += xChangeFinal;
    finalColor.y += yChangeFinal;
    finalColor.z += zChangeFinal;

  10. Clearly I've botched up something but I know not what. Any clues from the community would be greatly appreciated.

    My day/night textures load with vaoIDs 15 and 16 but I can't see them both at the same time. When bindTexture looks like this I get the day texture fading to/from black:
    private void bindTextures() {
    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture);
    //GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, nightTexture);

    When it looks like this I get the night texture fading to/from black:
    private void bindTextures() {
    //GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture);
    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, nightTexture);

    But when they're both uncommented my skybox is black all the time. Here's my fragment shader:
    #version 400
    in vec3 textureCoords;
    out vec4 out_Color;
    uniform samplerCube cubeMap1;
    uniform samplerCube cubeMap2;
    uniform float blendFactor;
    uniform vec3 fogColour;
    const float fogLowerLimit = 0.0;
    const float fogUpperLimit = 30.0;
    void main(void) {
    vec4 textureColour1 = texture(cubeMap1, textureCoords);
    vec4 textureColour2 = texture(cubeMap2, textureCoords);
    vec4 textureColour = mix(textureColour1, textureColour2, blendFactor);
    float fogFactor = (textureCoords.y – fogLowerLimit) / ( fogUpperLimit – fogLowerLimit);
    fogFactor = clamp(fogFactor, 0.0, 1.0);
    out_Color = mix(vec4(fogColour, 1.0), textureColour, fogFactor);

  11. Whaaaat 😮
    You accelarated the coding footage and did post commentary? I honestly tried to keep up with your coding speed while rushing through this inanely well made tutorial series.
    My fingers hurt now 😀

    Keep being as awesome!

  12. For anybody wondering a good way to change the fog color, I've found that having a separate variable to 'time' called 'fogTime', which progresses slower (DisplayManager.getFrameTimeSeconds() * 10), and '%=240' instead of 24000… and then (using the initial fog color in the tutorial):

    if( < 0.5404f){ = + ((0.5404f / 3000.0f) * (fogTime – 50));
    if( < 0.62f){ = + ((0.62f / 3000.0f) * (fogTime – 50));
    if( < 0.69f){ = + ((0.69f / 3000.0f) * (fogTime – 50));

    and just the opposite transitioning to night, testing if > 0 and then fogTime – 210 instead of 50, or whatever matches the system you have.

  13. I believe you can achieve the same exact transition from day to night sky with essentially one function call like so:

    blendFactor = (float) ((float) (Math.sin(Math.toRadians(time/delay))+1.0)/2.0);

    keeping constant:
    texture1 = nightTextureID;
    texture2 = dayTextureID;

    and adding a variable

    float delay;
    delay = 100;// this is a good transition speed.

    What's nice about this is that it's also easy to implement in the MainGameLoop to modulate the sun's intensity, synchronized with the skybox's cubemap texture blend intensity.

  14. When the cubeMap changes it changes brutally please help:
    private void bindTextures(){
    time += DisplayManager.getFrameTimeSeconds() * 1000;
    time %= 14000;
    int texture1;
    int texture2;
    float blendFactor;
    if(time >= 0 && time < 5000) {
    texture1 = nightTexture;
    texture2 = nightTexture;
    blendFactor = (time – 0) / (5000 – 0);
    }else if(time >= 5000 && time < 8000) {
    texture1 = nightTexture;
    texture2 = texture;
    blendFactor = (time – 5000) / (8000 – 5000);
    }else if(time >= 8000 && time < 21000) {
    texture1 = texture;
    texture2 = texture;
    blendFactor = (time -8000) / (21000 – 8000);
    }else {
    texture1 = texture;
    texture2 = nightTexture;
    blendFactor = (time – 21000) / (24000 – 21000);
    System.out.println("blendFactor: " + blendFactor + " time: " + time);

  15. +ThinMatrix How would I make the actual game-light slowly get brighter as the skybox becomes day? The same for night? You don't have any light changing. There's no sun!

  16. Here's my method. I decided that the trigonometric functions modeled what I wanted to do quite well so I adapted cos to my purposes:
    private static final double CYCLE_LENGTH is set to 8. It's just the cycle time in seconds, fast for testing purposes. I call it in the SkyboxRenderer.render() so it updates every frame with shader.loadBlendFactor(getBlendFactor());

    private float getBlendFactor() {
    timeSeconds += DisplayManager.getFrameTimeSeconds();
    return (float)Math.abs(.5f * Math.cos(- 1 *timeSeconds*2*Math.PI/CYCLE_LENGTH)-.5f);

    The *.5f shrinks the bounds of the cos(-x) function from -1:1 to -.5:.5. The -.5f then moves this down to bound between -1 and 0. The cos function starts at 0 and we modify the scale to our liking by multiplying out 2pi and dividing by the period we want to establish.

    If you wanted to start with the texture identified as 1 instead of 0 you could use the much simpler return (float).5f * Math.cos(timeSeconds*2*Math.PI/CYCLE_LENGTH)+.5f; and if you want it to start in the middle of the 2 skyboxes instead of one of the extrema use sin instead. If you want it to stay completely night/day for part of the cycle you can change the *.5f to .6f or .8f or something and then clamp it back to the [0,1] interval afterwards with basic math methods or if statements. Hope this helps someone ;P

  17. I have a problem with the cycle, change between day and night was brutal, no smoothie like in the video, do you have an idea?

  18. Hey! for anyone who wants a more refined look to the Day/Night System, here is what I've done, (copy paste into your Class files)

    MainGameLoop (inside while(!Display.isCloaeRequeasted()){}:
    if(SkyboxRenderer.time >= 0 && SkyboxRenderer.time < 5000){
    light.setColor(new Vector3f(0.3f,0.3f,0.3f));
    MasterRenderer.RED = 0.01f;
    MasterRenderer.GREEN = 0.01f;
    MasterRenderer.BLUE = 0.01f;
    }else if(SkyboxRenderer.time >= 5000 && SkyboxRenderer.time < 8000){
    light.increaseColor(new Vector3f(0.0001f,0.0001f,0.0001f));
    MasterRenderer.RED += 0.00157f;
    MasterRenderer.GREEN += 0.00157f;
    MasterRenderer.BLUE += 0.0018f;
    }else if(SkyboxRenderer.time >= 8000 && SkyboxRenderer.time < 21000){
    light.setColor(new Vector3f(1f,1f,1f));
    MasterRenderer.RED = 0.5444f;
    MasterRenderer.GREEN = 0.62f;
    MasterRenderer.BLUE = 0.69f;
    light.decreaseColor(new Vector3f(0.0001f,0.0001f,0.0001f));
    MasterRenderer.RED -= 0.002f;
    MasterRenderer.GREEN -= 0.002f;
    MasterRenderer.BLUE -= 0.002f;

    inside Light Class:

    private float lightValueChange = 0.0019;

    public void increaseColor(Vector3f colorIncrease){
    colorIncrease = new Vector3f(getColor().x+lightValueChange,getColor().y+lightValueChange,getColor().z+lightValueChange);
    setColor(new Vector3f(colorIncrease.x,colorIncrease.y,colorIncrease.z));
    public void decreaseColor(Vector3f colorDecrease){
    colorDecrease = new Vector3f(getColor().x-lightValueChange,getColor().y-lightValueChange,getColor().z-lightValueChange);
    setColor(new Vector3f(colorDecrease.x,colorDecrease.y,colorDecrease.z));

    Hope you found this helpful!!

  19. @ThinMatrix 
    Are you going to do like an alpha, pre-alpha release, or anything like that with your game?

  20. Hi.I am Russian. And I do not understand the English language , but you are my idol , well done , thank you , good luck in development!!


Please enter your comment!
Please enter your name here