I am attempting to implement a day/night cycle using a GLSL fragment shader in a 2D game i'm developing in SFML. I am a novice with shaders with this one being my first.

Currently I am using a lightmap to achieve ambient lighting and spotlights from lightsources (e.g. campfire) which is working nicely. The lightmap shader I am using I got from following an old Alcovegames tutorial, see below:

uniform sampler2D texture;
uniform sampler2D lightmap;

uniform vec4 ambient;
uniform vec2 resolution;
uniform int theta;

float PI_180 = 3.141592653589793 / 180;

vec3 ToGlColour3(in vec3 colour)
    float dv = (1.0/255);
    return vec3
        dv * colour.r,
        dv * colour.g,
        dv * colour.b

vec4 ToGlColour4(in vec4 colour)
    return vec4
        (1.0/255) * colour.a

void main()
    vec4 diffuse = texture2D(texture, gl_TexCoord[0].xy);

    vec2 lightcoord = (gl_FragCoord.xy / resolution.xy);
    vec4 light = texture2D(lightmap, lightcoord);

    vec4 ambientLight = ToGlColour4(ambient);

    float ambientIntensity = ambientLight.a * (sin(theta * PI_180) + 0.5);
    vec3 ambientColour = ambientLight.rgb * ambientIntensity;
    vec3 intensity = (ambientColour + light.rgb);

    vec3 result = diffuse.rgb * intensity;

    gl_FragColor = vec4(result, diffuse.a);

The ambientIntesity calculation is my attempt at cycling from night to day. My issue is that it doesn't cycle bright enough to give an adequate daytime effect.

I was thinking I could use the current value of sine(theta) and interpolate from my ambient colour to white (representing fully lit daytime).

I'm just not sure how to achieve this in GLSL. Ideally a solution within GLSL would be possible to help develop my knowledge of shaders.

I appreciate any help, Thanks.

  • \$\begingroup\$ Why are you multiplying your ambient color's alpha and color channels by 1/255.0? That's going to make them very small. Also, it's wasteful as you're doing that calculation on every fragment. You should just scale it before passing setting the uniform. \$\endgroup\$ – user1118321 Jul 14 '18 at 3:17
  • \$\begingroup\$ @user1118321 I use those methods for normalising the colours that i pass into the shader as they are between 0-255. I understand that it is wasteful, but for now while i'm learning, i'm not too interested in optimisations until i have the shader working as intended, but thanks for pointing it out, i'll make the change now \$\endgroup\$ – cmpbedes Jul 16 '18 at 7:52

you are scaling the ambient lighting by a factor of [-0.5, 1.5]. Ambient light is generally a small value, because it is meant to add a small amount of light to fragments that would otherwise show up as black due to the lightmap. What you want to do is scale the light.rgb color in the range [0,n] where the value of n*light.rgb is the sunlight at peak daytime.

vec3 result = (ambientLight.rgb + n*(sin(...)*0.5+0.5)*light.rgb;
  • \$\begingroup\$ Thanks for providing this solution, could you just clarify where the value of n is coming from? \$\endgroup\$ – cmpbedes Jul 16 '18 at 7:58
  • \$\begingroup\$ n is just a scale factor for the light value coming from the lightmap texture. Alternatively, you could remove n and scale each pixel rgb value in the texture by n. \$\endgroup\$ – Kyy13 Jul 16 '18 at 17:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.