EDIT
I have discovered that it does not seem to be the lighting calculation but the culling code because when i draw the lights without the culling it works perfectly.
I have been attempting to implement tile based deferred light culling using this as a guide. My current issue is that the lights don't seem to be drawing correctly. I have tested that the lights per tile are correct and they are and the light indices for each tile seem to be correct too. When I draw the scene I get allot of the tiles affected by point lights flickering every frame. I also dont think that the point lights are being rendered in there correct positions.
Here is what I am testing at the moment.
I construct the point light array to be sent to the compute shader.
for (int y = 32; y < 32; y++) {
for (int x = 0; x < 32; x++) {
pointLights[x + y * 32] = new PointLight(new Vector3f(x, y, 0);
}
}
All of theses point lights are sent to the uniform array and the scene is drawn.
As you can see I am using 1024 lights but what I see is only one light affecting my 32 * 32 plane right in the center and when I test what tiles are affected by the light it is correct. These lit tiles also flicker every other frame.
So where did I go wrong Is it in my light culling code, my lighting functions, or something else completely.
Here is my complete 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;
float atten = 1.0 / (pointLight.atten.constant + pointLight.atten.linear * distanceToPoint + pointLight.atten.exponent * (distanceToPoint * distanceToPoint));
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;
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(1.0f / pointLightCount);
}
barrier();
imageStore(finalImage, pixel, color);
}