DevLog #008 – Night & Day

Part of a series of posts in which we write a voxel engine from scratch for Android.

It might seem too early in the project to add a day/night cycle, but we needed a sky, and a simple skybox wasn’t gonig to cut it, so this quickly escalated into exactly that.

Getting picture-perfect lighting at every hour of the day is no easy task, so what we needed was a system that could interpolate between sunlight, ambient light, fog and light-scatter at various pre-set points of the day which can be manually tweaked to produce the best results at say, noon or sunset, and let the math fill in the gaps.

So we can define exactly how the lighting will look at 5,6 & 7am for a sunrise, and how it will look at 12pm for midday, and the engine can use linear interpolation to know how it should look at 9:45am for example.

We can define the lighting for 7am like this..

            new Time(7,0.344f,0.34f,0.33f          //Ambient
                    ,0.8f,0.8f,0.8f                //Sunlight
                    ,45.0f,30.0f                   //Sun Direction
                    ,0.25f,0.55f,0.9f              //Sky Color
                    ,0.35f,0.55f,0.9f              //Fog Color
                    ,100.0f,0.0f                   //Fog Distance & Thickness
                    ,0.5f                          //Sky Overcast
                    ,1.0f                          //Cloud Thickness
                    ,-0.2f                         //Cloud Height
                    ,0.0f,0.2f);                   //Stars Gamma,Sunlight Scatter

..and for any hours of the day that don’t need drastic lighting changes (say, 1-3pm) can be defined simply by interpolating the hours that book-end them like so…

Time.addLerpTime(13,15);   //add hours for 13,14,15 by lerping from 12-16

We can then take the game time in hours,minutes and seconds to calculate smooth transitions in lighting…

float lerp=((float)minute/60.0f)+(second/(60.0f*60.0f));
for (int i=0; i < 3; i++) {
    ambient_col[i]=(Time.getHour(hour).ambient_col[i]*(1.0f-lerp))+(Time.getHour(hour+1).ambient_col[i]*lerp);
}

This can result in drastically different atmosphere depending on the time of day…

The skybox, rather than just being a basic texture, has a grey-scale texture that is re-colored by our lighting calculation for the sky color, and an alpha-channel to blend-in the fog color from the horizon, which has the side-effect of making our fog look more natural.

The skybox is rendered in one draw-call using the alpha channel (shown in pink) for fog color, and the greyscale for sky-color depending on time of day

To avoid too much repetition in our starbox texture, we overlay a noise texture to reduce the brightness of stars – which can be moved around to make the stars twinkle independently. This is then additive-blended with our skybox.

The star occlusion-map (right) reduces repetition in the stars texture, and can be shifted around to make the stars twinkle

Lighting is far from complete, but we now have a pretty good starting point to work from. Watch this space for more on this subject in a future post.