3
\$\begingroup\$

I'm trying to implement tile based light culling in opengl using a compute shader. I am using this as a guide. The lighting calculations work fine but the point light culling doesn't seem to work any where near correctly. I can't tell if my planes are calculated wrong or its my culling loop. To test what tile has a light affecting it I draw it in gray, as i move the camera away the gray tiles fade to the right no matter where the light is placed.

Compute shader:

#version 430

#define MAX_POINT_LIGHTS 1024
#define MAX_LIGHTS_PER_TILE 40
#define WORK_GROUP_SIZE 16

struct Attenuation
{
    float constant;
    float linear;
    float exponent;
};

struct Light
{
    vec3 color;
    float intensity;
};

struct DirectionalLight
{
    Light light;
    vec3 direction;
};

struct PointLight
{
    Light light;
    Attenuation atten;
    vec3 position;
    float radius;
};

vec4 calcLight(Light light, vec3 direction, vec3 normal, vec3 fragPos, vec3 specular, vec3 camPos)
{
    float diffuseFactor = dot(normal, -direction);

    vec4 diffuseColor = vec4(0.0, 0.0, 0.0, 0.0);
    vec4 specularColor = vec4(0.0, 0.0, 0.0, 0.0);

    if (diffuseFactor > 0)
    {
        // might need to be 0.0----------| |
        diffuseColor = vec4(light.color, 1.0) * light.intensity * diffuseFactor;

        vec3 directionToEye = normalize(camPos - fragPos);
        vec3 halfDirection = normalize(directionToEye - direction);

        float specularFactor = dot(halfDirection, normal);
        // maybe not 32?
        specularFactor = pow(specularFactor, 32);

        if (specularFactor > 0)
        {
            // maybe 0.0 again
            specularColor = vec4(light.color, 1.0) * vec4(specular, 1.0) * specularFactor;
        }
    }

    return diffuseColor + specularColor;
}

vec4 calcDirectionalLight(DirectionalLight dirLight, vec3 pos, vec3 normal, vec3 specular, vec3 camPos)
{
    return calcLight(dirLight.light, dirLight.direction, normal, pos, specular, camPos);
}

vec4 calcPointLight(PointLight pointLight, vec3 pos, vec3 normal, vec3 specular, vec3 camPos)
{
    vec3 lightDirection = pos - pointLight.position;
    float distanceToPoint = length(lightDirection);

    lightDirection = normalize(lightDirection);

    vec4 color = calcLight(pointLight.light, lightDirection, normal, pos, specular, camPos);

    float atten = pointLight.atten.constant + pointLight.atten.linear * distanceToPoint + pointLight.atten.exponent * distanceToPoint * distanceToPoint + 0.0001;

    return color / atten;
}

layout (binding = 1, rgba32f) uniform image2D writeonly finalImage;
layout (binding = 2, rgba32f) uniform readonly image2D geometryPosition;
layout (binding = 3, rgba32f) uniform readonly image2D geometryDiffuse;
layout (binding = 4, rgba32f) uniform readonly image2D geometryNormal;

uniform int numActiveLights;
uniform PointLight pointLights[MAX_POINT_LIGHTS];
uniform Light ambientLight;
uniform DirectionalLight directionalLight;

uniform vec3 cameraPosition;
uniform vec2 resolution;

uniform mat4 projection;
uniform mat4 view;

shared uint minDepth;
shared uint maxDepth;
shared uint pointLightCount;
shared uint pointLightIndex[MAX_POINT_LIGHTS];

layout (local_size_x = WORK_GROUP_SIZE, local_size_y = WORK_GROUP_SIZE) in;

void main()
{
    minDepth = uint(0xFFFFFFFF);
    maxDepth = 0;
    pointLightCount = 0;
    barrier();

    ivec2 pixel = ivec2(gl_GlobalInvocationID.xy);

    vec3 position = imageLoad(geometryPosition, pixel).xyz;
    float d = position.z;
    uint depth = uint(d * uint(0xFFFFFFFF));

    atomicMin(minDepth, depth);
    atomicMax(maxDepth, depth);

    barrier();

    float minDepthZ = float(minDepth / float(0xFFFFFFFF));
    float maxDepthZ = float(maxDepth / float(0xFFFFFFFF));

    vec2 tileScale = vec2(resolution * (1.0 / float(2 * WORK_GROUP_SIZE)));
    vec2 tileBias = tileScale = vec2(gl_WorkGroupID.xy);

    vec4 col1 = vec4(-projection[0][0] * tileScale.x, projection[0][1], tileBias.x, projection[0][3]);
    vec4 col2 = vec4(projection[1][0], -projection[1][1] * tileScale.y, tileBias.y, projection[1][3]);
    vec4 col4 = vec4(projection[3][0], projection[3][1], -1.0, projection[3][3]);

    //vec4 col1 = vec4(-projection[0][0] * tileScale.x, 0.0f, tileBias.x, 0.0f);
    //vec4 col2 = vec4(0.0f, -projection[1][1] * tileScale.y, tileBias.y, 0.0f);
    //vec4 col4 = vec4(0.0, 0.0, 1.0, 0.0);

    vec4 frustumPlanes[6];
    frustumPlanes[0] = col4 + col1;
    frustumPlanes[1] = col4 - col1;
    frustumPlanes[2] = col4 - col2;
    frustumPlanes[3] = col4 + col2;
    frustumPlanes[4] = vec4(0.0, 0.0, -1.0, -minDepthZ);
    frustumPlanes[5] = vec4(0.0, 0.0, -1.0, maxDepth);

    for (int i = 0; i < 4; i++)
    {
        frustumPlanes[i] *= 1.0 / length(frustumPlanes[i].xyz);
    }

    uint threadCount = WORK_GROUP_SIZE * WORK_GROUP_SIZE;
    uint passCount = (numActiveLights + threadCount - 1) / threadCount;

    for (int passIt = 0; passIt < passCount; ++passIt)
    {
        uint lightIndex = passIt * threadCount + gl_LocalInvocationIndex;
        lightIndex = min(lightIndex, numActiveLights);

        PointLight p = pointLights[lightIndex];
        vec4 pos = view * vec4(p.position, 1.0);
        float rad = p.radius / pos.w;

        if (pointLightCount < MAX_LIGHTS_PER_TILE)
        {
            bool inFrustum = true;
            for (int i = 3; i >= 0 && inFrustum; i--)
            {
                float dist = dot(frustumPlanes[i], pos);
                inFrustum = (-rad <= dist);
            }

            if (inFrustum)
            {
                uint id = atomicAdd(pointLightCount, 1);
                pointLightIndex[id] = lightIndex;
            }
        }
    }

    barrier();

    vec3 normal = imageLoad(geometryNormal, pixel).xyz;
    vec4 diffuse = imageLoad(geometryDiffuse, pixel);
    vec3 specular = vec3(0.1, 0.1, 0.1);

    vec4 color = diffuse;
    color *= vec4((ambientLight.color * ambientLight.intensity), 1.0);
    color += calcDirectionalLight(directionalLight, position, normal, specular, cameraPosition);

    for (int i = 0; i < pointLightCount; i++)
    {
        //color += calcPointLight(pointLights[pointLightIndex[i]], position, normal, specular, cameraPosition);
        color = vec4(0.5);
    }

    barrier();

    imageStore(finalImage, pixel, color);
}
\$\endgroup\$
1
\$\begingroup\$

Turns out it was just a stupid mistake on the line

vec2 tileBias = tileScale = vec2(gl_WorkGroupID.xy);

The second "=" should be "-". Whoops! Every thing works fine now.

\$\endgroup\$

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.