Search code examples
c++openglglsl2dlighting

Resizing window cause my 2D Lighting to stretch


I am trying to implement a simple artificial 2D lighting. I am not using an algorithm like Phong's. However, I am having some difficulty in ensuring that my lighting do not stretch/squeeze whenever the window resize. Any tips and suggestions will be appreciated. I have tried converting my radius into a vec2 so that I can scale them accordingly based on the aspect ratio, however it doesnt work properly. Also, I am aware that my code is not the most efficient, any feedback is also appreciated as I am still learning! :D

I have an orthographic projection matrix transforming the light position so that it will be at the correct spot in the viewport, this fixed the position but not the radius (as I am calculating per fragment). How would I go about transforming the radius based on the aspect ratio?

void LightSystem::Update(const OrthographicCamera& camera)
{
    std::vector<LightComponent> lights;
    for (auto& entity : m_Entities)
    {
        auto& light = g_ECSManager.GetComponent<LightComponent>(entity);
        auto& trans = g_ECSManager.GetComponent<TransformComponent>(entity);
        if (light.lightEnabled)
        {
            light.pos = trans.Position;
            glm::mat4 viewProjMat = camera.GetViewProjectionMatrix();
            light.pos = viewProjMat * glm::vec4(light.pos, 1.f);
            // Need to store all the light atrributes in an array
            lights.emplace_back(light);
        }
        // Create a function in Render2D.cpp, pass all the arrays as a uniform variable to the shader, call this function here
        glm::vec2 res{ camera.GetWidth(), camera.GetHeight() };
        Renderer2D::DrawLight(lights, camera, res);

    }
}

Here is my shader:

#type fragment
#version 330 core
layout (location = 0) out vec4 color;

#define MAX_LIGHTS 10
uniform struct Light
{
    vec4 colour;
    vec3 position;
    float radius;
    float intensity;
} allLights[MAX_LIGHTS];

in vec4 v_Color;
in vec2 v_TexCoord;
in float v_TexIndex;
in float v_TilingFactor;
in vec4 fragmentPosition;

uniform sampler2D u_Textures[32];
uniform vec4 u_ambientColour;
uniform int numLights;
uniform vec2 resolution;

vec4 calculateLight(Light light)
{
    float lightDistance = length(distance(fragmentPosition.xy, light.position.xy));

    //float ar = resolution.x / resolution.y;

    if (lightDistance >= light.radius)
    {
        return vec4(0, 0, 0, 1); //outside of radius make it black
    }
    return light.intensity * (1 - lightDistance / light.radius) * light.colour;
}

void main()
{   
    vec4 texColor = v_Color;

    vec4 netLightColour = vec4(0, 0, 0, 1);
    if (numLights == 0)
        color = texColor;
    else
    {
        for(int i = 0; i < numLights; ++i) //Loop through lights
            netLightColour += calculateLight(allLights[i]) + u_ambientColour;
        color = texColor * netLightColour;
    }
}


Solution

  • I'm going to compile all the answers for my question, as I had done a bad job in asking and everything turned out to be a mess.

    As the other answers suggest, first I had to use an orthographic projection matrix to ensure that the light source position was displayed at the correct position in the viewport.

    Next, from the way I did my lighting, the projection matrix earlier would not fix the stretch effect as my light wasn't an actual circle object made with actual vertices. I had to turn radius into a vec2 type, representing the radius vectors along x and y axis. This is so that I can then modify the vectors based on the aspect ratio:

    if (aspectRatio > 1.0)
        light.radius.x /= aspectRatio;
    else
        light.radius.x /= aspectRatio;
    

    I had posted another question here, to modify my lighting algorithm to support an ellipse shape. This allowed me to then perform the scalings needed to counter the stretching along x/y axis whenever my aspect ratio changed. Thank you all for the answers.