0
\$\begingroup\$

I setup simple single light source lighting around campfire object. However, as can be seen, the transition between lightened area and unlighted one is sharp.

enter image description here

The GLSL fragment shader code:

uniform vec2 screenSize;
uniform vec2 lightSourceSize;
uniform vec2 lightSourceCoords;
uniform float lightIntensityCap;
uniform sampler2D textureSample;

void main(void)
{
    float horizontalDiff = -lightSourceSize.x / 2;
    float verticalDiff = lightSourceSize.y;

    float lightSourceX =
    (lightSourceCoords.x - horizontalDiff) / screenSize.x * 2 - 1;

    float lightSourceY =
    (-lightSourceCoords.y - verticalDiff) / screenSize.y * 2 + 1;

    vec2 lightSourcePos = vec2(lightSourceX, lightSourceY);

    float lightIntensity = 1.0/distance(lightSourcePos, pos.xy);

    if (lightIntensity >= lightIntensityCap) {
        lightIntensity = lightIntensityCap;
    }

    if (lightIntensity <= 1) {
        lightIntensity = 1;
    }

    if (distance(lightSourcePos, pos.xy) > 0.3) {
        lightIntensity = 1;
    }

    vec4 lightCol = vec4(lightIntensity, lightIntensity, lightIntensity, 1.0);
    fColor = texture(textureSample, fragmentUV).rgba * lightCol;

    if (fColor.a <= 0){
        discard;
    }
}

If I will remove

if (distance(lightSourcePos, pos.xy) > 0.3) {
    lightIntensity = 1;
}

the lightened area will expand and the transition will be much smoother. How do I interpolate light intensity and achieve smooth transition for smaller area?

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

I managed to do it. The key is to use diffusion and ambient light values. If the distance is less than radius of target lightened area, the light should be diffused and combined with ambient.

In case of fragment being too far away from light source, ambient is used to set default light value.

vec2 lightSourcePos = vec2(lightSourceX, lightSourceY);

vec3 ambient = vec3(0.8, 0.8, 0.8);

float dist = distance(lightSourcePos, pos.xy);
float lightIntensity = 1.0/dist;
float targetRadius = 0.3;
float diffuse = 0;

if(dist < targetRadius) {
    diffuse = 1.0 - abs(dist / targetRadius);
}

if (lightIntensity >= lightIntensityCap) {
    lightIntensity = lightIntensityCap;
}

if (lightIntensity <= 1) {
    lightIntensity = 1;
}

vec4 fragColor = texture(textureSample, fragmentUV).rgba;
vec3 lightCol = vec3(lightIntensity, lightIntensity, lightIntensity);
fColor = vec4(min(fragColor.rgb * ((lightCol * diffuse) + ambient), fragColor.rgb), 1.0);

enter image description here

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .