I'm using a fragment shader to implement 2D lighting (code further below). Even though I am satisfied with the visuals of the light i noticed that it has a quite big GPU usage, and when trying to add about 40+ light sources the usage is close to 100% (GTX 1050).

I have a uniform array of structs that contain data about each light source and for loop that goes through all of them.

At first I thought I was pushing too much data to the GPU so I combined the RGB values of the light color in a single 32 bit integer and the two strengths of the light in a single 32 bit integer as well. Then I tried simplifying the formulas I used (using a composed, by composed I'm not referring to the operation, function from multiple linear functions) but it seemed that just made the matters worse.

I think it's worth noting the difference between LightStrength and VisualStrength values that I used in the code, the LightStrength is the strength of the light that lights up the medium around it and the VisualStrength is the strength of the colored hue around the light. And there is also a dark hue variable that is used to make the scene darker as of in the different times of the day.

The code of the fragment shader:

#version 450 core

in vec2 texCoord0;
uniform vec3 CameraPosition;
uniform mat4 Projection;
uniform float DarkHue;

uniform sampler2D u_Texture;
uniform vec2 u_resolution;

struct LightSource {
    vec2 Position;
    int LightColor;
    int ArgumentValue;

uniform LightSource LightSources[300];
uniform int LightSourceCount;

float GetLightfactor(float x,float Streght) {
    return min(1/(x*(Streght/100.0)+1),1);

void main() {
    gl_FragColor = texture2D(u_Texture,texCoord0);

    vec3 LightSum = vec3(0);
    vec4 PCameraPosition = vec4(CameraPosition,0) * Projection;

    vec2 NormalizedPosition = gl_FragCoord.xy*2/u_resolution-1;

    float LightFactor,VisualFactor,LightStreght,VisualStreght;

    for (int i = 0;i < LightSourceCount;++i) {

        vec4 Pos = vec4(LightSources[i].Position,0,0) * Projection + PCameraPosition; 

        vec2 coord = (NormalizedPosition-Pos.xy) * u_resolution;
        LightFactor = 0.0;
        VisualFactor = 0.0;

        LightStreght = LightSources[i].ArgumentValue & 0xffff;
        VisualStreght = (LightSources[i].ArgumentValue >> 16) & 0xffff;

        float lng = length(coord);

        LightFactor = GetLightfactor(lng,LightStreght);
        VisualFactor = GetLightfactor(lng,VisualStreght);

        LightSum = mix(LightSum,vec3(1),gl_FragColor.rgb * LightFactor * (1-DarkHue)) + vec3(((LightSources[i].LightColor >> 16)&0xff)/255.0,((LightSources[i].LightColor >> 8)&0xff)/255.0,(LightSources[i].LightColor&0xff)/255.0) * VisualFactor;


    gl_FragColor.rgb *= DarkHue;
    gl_FragColor.rgb += LightSum;

The code of the c++ function that adds a light source. (Yes when setting uniforms caching is used)

static void AddLightSource(Vec2 Position, uint8_t R, uint8_t B, uint8_t G, uint16_t LightStrenght,uint16_t VisualStrenght) {
        std::string access = "LightSources[" + std::to_string(ActiveLightSources) + "]";
        int Value = (VisualStrenght << 16) | LightStrenght;
        int Color = (R << 16) | (G << 8) | B;
        Vec3 Translated = VertexArrayManager::TranslateValue;
        shader->setUniform2f(access + ".Position", glm::vec2(Position.x+Translated.x,Position.y + Translated.y));
        shader->setUniform1i(access + ".LightColor", Color);
        shader->setUniform1i(access + ".ArgumentValue", Value);
        shader->setUniform1i("LightSourceCount", ActiveLightSources);
  • 2
    \$\begingroup\$ It looks like you've written a forward renderer. These are known to scale quite poorly as the number of lights increases. Have you looked into deferred or forward+ rendering (effectively, forward rendering with tile-based optimizations via compute shaders)? These approaches are designed to have much better performance when there are many lights that affect only part of the view. \$\endgroup\$
    – DMGregory
    Nov 5 '20 at 13:02
  • \$\begingroup\$ I looked up the methods you suggested and it looks like it will solve the problem. Thanks. \$\endgroup\$ Nov 5 '20 at 23:56
  • \$\begingroup\$ @BananaFructa IMHO the best way to thank DMGregory is to eventually post an answer with some of your findings and/or a link to the code if open. \$\endgroup\$
    – Vorac
    Nov 10 '20 at 3:59
  • \$\begingroup\$ I will once i eventually implement it and get it working. \$\endgroup\$ Nov 10 '20 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.