I am creating a shader in c++ with a resizable amount of lights I can pass to the shader. It seems I can pass a std::vector to a glsl array using SSBO, a feature implemented in modern OpenGL 4.2. I started by setting the glsl version to 460 core
(#version 460 core
). After that I created a lights array of type Light:
#define LIGHT_DIRECTIONAL 0
#define LIGHT_POINT 1
struct Light
{
int type;
bool enabled;
vec3 position;
vec3 relative_position;
vec3 target;
vec4 color;
float attenuation;
bool isChild;
};
layout(std430, binding = 0) buffer LightsBuffer
{
Light lights[];
};
Then I initialized my SSBO as follow:
void InitLighting()
{
Vector4 ambientLight = {0.2f, 0.2f, 0.2f, 1.0f};
SetShaderValue(shader, GetShaderLocation(shader, "ambientLight"), &ambientLight, SHADER_UNIFORM_VEC4);
GLuint shaderProgramID = shader.id; // Obtain the shader program ID from the Shader object
glGenBuffers(1, &lightsBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, lightsBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Light) * lights.size(), lights.data(), GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, lightsBuffer); // Update the binding point to 3
// Set the lightsCount uniform
int lightsCount = lights.size();
glUniform1i(GetShaderLocation(shader, "lightsCount"), lightsCount);
}
And when I create a new light I update my glsl array:
GLuint lightsBuffer;
vector<Light> lights;
vector<AdditionalLightInfo> lights_info;
Light NewLight(const Vector3 position, const Color color)
{
glm::vec3 lights_position = glm::vec3(position.x, position.y, position.z);
glm::vec4 lights_color = glm::vec4(color.r/255, color.g/255, color.b/255, color.a/255);
Light light;
light.position = lights_position;
light.color = lights_color;
lights.push_back(light);
AdditionalLightInfo info;
info.name = "Light";
lights_info.push_back(info);
return lights.back();
}
void UpdateLightsBuffer()
{
// Convert light colors to the range of 0-1
for (Light& light : lights) {
light.color.r /= 255.0f;
light.color.g /= 255.0f;
light.color.b /= 255.0f;
light.color.a /= 255.0f;
}
glBindBuffer(GL_SHADER_STORAGE_BUFFER, lightsBuffer);
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(Light) * lights.size(), lights.data());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, lightsBuffer); // Bind the SSBO to binding point 0
int lightsCount = lights.size();
SetShaderValue(shader, GetShaderLocation(shader, "lightsCount"), &lightsCount, SHADER_UNIFORM_INT);
}
My problem stays on updating the lights array in my glsl frag shader. It seems the lights array never changes, which means I updated the SSBO array wrongly in the UpdateLightsBuffer
function.
Additionally my shader compiles successfully:
INFO: SHADER: [ID 1] Vertex shader compiled successfully
INFO: SHADER: [ID 2] Fragment shader compiled successfully
INFO: SHADER: [ID 3] Program shader loaded successfully
INFO: SHADER: [ID 3] Default shader loaded successfully
I expect the shader to make the lights cast a basic lighting effect on every entities. I don't want to set a max amount of lights because I want the user to add as many lights as they want in realtime, it can be 1, 10, 100, 1000 or even 2000+.
I also tried to follow this solution from other post but with no luck: https://stackoverflow.com/a/50549567/11647955
This is also not a duplicate of: Should I ever use a `vec3` inside of a uniform buffer or shader storage buffer object? I am not interested in UBO, only SSBO.