Search code examples
openglglsltexturestexture-mapping

Cross-fade between two textures on a sphere


I have a 3D scene with only one sphere in it and I have two textures - one for the night, and one for the day of this planet. In addition I have the a lightSource at (15,15,15) in my scene. For each vertex on the sphere I also have the normal.

Now I want to blend between the two texture so that the fading between day and night seems to be realistic. Therefore I calculate the angle between the normal and the light using dot-product, but with this approach I get hard crossover if I check if the angle is > 0 (which will be the dayside). I need to mix the textures based on the angle, that it is a soft crossover.

Can anyone help me how I can mix the textures? My code so far:

float angle = dot(L,N);
vec4 texture = texture2D(day, textureCoord);         

texture = texture2D(night,textureCoord) * (1-angle)  +  texture * angle;
vec4 light = vec4(ambientTerm + diffuseTerm + specularTerm , 1);

if(angle > 0) {
    color = light * texture;
} else if(angle >= -0.25) {
    color = texture2D(night,textureCoord)*(angle-1) + texture * (angle);
} else if( angle < -0.25) {
    color = texture2D(night,textureCoord);
}

Solution

  • You can use the smoothstep function to turn a continous value into a 0/1 decision with a small smooth transition in between. So basically you define a range where the transisition is, let's just take [-0.25,0.25], which would be an angle range from about 75 to 105 degrees (take larger values for a larger transistion area, but try to make it symmetrical, thus centered around 90 degrees, since people switch on their lights at dusk already ;)). Then we transform our [-1,1] monotonic cosine using

    angle = smoothstep(-0.25, 0.25, angle)
    

    which will result in angle (though that name is a bit unfortunately chosen, given that it isn't an angle and behaves inverse to the actual angle) being 0 if it was < -0.25, 1 if it was > 0.25 and a smooth transition if in between. And the whole texturing would look like (cleaned from the strange if and making use of the builtin mix function):

    float angle = dot(N, L);
    vec4 nightColor = texture2D(night, textureCoord);
    vec4 dayColor = texture2D(day, textureCoord);
    color = light * mix(nightColor, dayColor, smoothstep(-0.25, 0.25, angle));
    

    Or, for the fun and sake of completeness the more streamlined

    color = light * mix(texture2D(night, textureCoord), 
                        texture2D(day, textureCoord), 
                        smoothstep(-0.25, 0.25, dot(N, L)));