0

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.

Lixt
  • 201
  • 4
  • 19

0 Answers0