I'm trying to cast shadows from a 1D texture that goes from white to back according to the distance given by an occlusion map. That part I think I got it right. The problem lies on the algorithm to check if a given pixel is in shadow.

Image of shadow showing hard cutoff

As you can see, the outer limits are clamped, as if it is in shadow. The result I would expect is that it would slowly fade. I don't know why my shader yields this result.

Here is the shader I use for casting the shadows:

#version 330
#define numTextures 32
#define PI 3.14

in vec2 TexCoords;
in vec4 pass_colors;
in vec4 fragPos;
in vec4 worldFragPos;
in mat4 outWorld;

out vec4 color;
uniform vec4 ambientColor;   
uniform sampler2D texture_diffuse;
uniform float radius;
uniform vec2 screenResolution;
uniform int lightCounter;

struct LightData
    float radius;
    vec3 position;        //light position, normalized
    vec4 color;      //light RGBA -- alpha is intensity

uniform LightData lights[numTextures];
uniform sampler2D shadows;

float n3ddistance(vec3 first_point, vec3 second_point)
    float x = first_point.x-second_point.x;
    float y = first_point.y-second_point.y;
    float val = x*x + y*y;
    return sqrt(val);

float sample(vec2 coord, float r) {
    return step(r, texture(shadows, coord).r);

float GetShadow(int lightIndex)
    vec2 dir = fragPos.xy - lights[lightIndex].position.xy;
    dir /= lights[lightIndex].radius / 2;
    //rectangular to polar
    dir.y *= -1;
    vec2 norm = dir.st;// * 2.0 - 1.0;
    float theta = atan(norm.y, norm.x);
    float r = length(norm);
    float coord = (theta + PI) / (2.0*PI);

    //the tex coord to sample our 1D lookup texture 
    //always 0.0 on y axis
    vec2 tc = vec2(coord, 0.0);

    return sample(tc, r); 

vec3 GetColor(int lightIndex)
    float dst = n3ddistance(lights[lightIndex].position.xyz, fragPos.xyz);
    float intensity = clamp(1.0 - dst / lights[lightIndex].radius, 0.0, 1.0);
    vec3 color = lights[lightIndex].color.rgb * intensity * GetShadow(lightIndex);
    return color;

void main()
    vec4 DiffuseColor = vec4(texture(texture_diffuse, TexCoords)) * pass_colors;

    vec3 sum = vec3(0);
    for(int i = 0; i < lightCounter; i++)
        sum += GetColor(i);

    vec3 intensity = ambientColor.xyz + sum;
    vec3 finalColor = DiffuseColor.rgb * intensity;
    color = vec4(finalColor.rgb, DiffuseColor.a);
    if (color.a <= 0.0) 

And here is the shader responsable for writing to that 1D texture

#version 330

#define PI 3.14159265359

in vec2 TexCoords;
in vec4 fragPos;
in vec3 lightPos;

out vec4 color;

uniform float radius;
uniform sampler2D occlusion;

void main()
    float distance = 1;

    for (float y=0.0; y < radius; y += 1.0)
        vec2 norm = vec2(TexCoords.s, y / radius) * 2.0 - 1.0;
        float theta = PI * 1.5 + norm.x * PI; 
        float r = (1.0 + norm.y) * 0.5;
        vec2 coord = vec2(-r * sin(theta), -r * cos(theta))/2.0 + 0.5;
        vec4 data = texture(occlusion, coord);
        float dst = y/radius;
        float caster = data.r;
        if (caster > 0.75) {
            distance = min(distance, dst);
  color = vec4(vec3(distance), 1.0);

How can I get a smooth fall-off instead of this sudden stop at a particular radius?


enter image description here

So It seems I has to use this line

 return sample(tc, r)* smoothstep(1.0, 0.0, r); 

which solves the problem...Thank you!


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.