Basic Point Light Implementation

Over the past few weeks I have been working on Implementing an easy to use and efficient light system for Supernova Softworks' game Project Neon, a puzzle platformer where the ability to freeze one color in the level is the main mechanic of the game. Using what I've learned from my work in the past and the tutorials on learnOpenGL I have been able to get the bedrock for my lighting system. I did need to convert some of the logic in the tutorials to 2D instead of its default 3D, but i feel the result is worth it. So far I have successfully implemented point lights and spot lights along with a system to handle multiple of each. For this post I will be writing about my understanding of Point Lights.

Point Lights

Point lights are the simpler of the two lights I have implemented. Consisting of a position, the light's color, also known as diffuse, and variables to determine the falloff of the light which I will explain later, point lights have a very simple implementation.

Beginning with the ambient light, which every manually or procedurally placed  light has within the rendering distance of most graphics programs, is the light that reaches the objects beyond the primary reach of the point light. The ambient light's strength is generally low. LearnOpenGL uses .1 as the ambient strength and in my program I used .01. If the ambient strength is too high then the objects that should be outside of the light's reach will seem lit. To determine the ambient light simply scale the point light's color by your chosen ambient strength and save it for later.

In the fragment part of the shader program, I pass it uniform values for all the variables within my point light struct in the non shader portion of my code, along with the current fragment position from the vertex part of the shader program, the light that reaches the fragment is calculated through dividing the lights color by a quadratic equation using the distance from the light's position to the fragment's position as x.

The previously unnamed variables that were passed to the shader program from each point light to the shader program are the constant(C), linear(L), and quadratic(Q) falloffs. The constant falloff controls the maximum amount of light near the center of the point light, while the linear and quadratic falloffs control the rate at which that the light decreases. This is called the light's attenuation and is determined with the equation: 1 / (C + LX + QX^2). The quadratic equation is placed under 1 due to the fact that the vector (in glm a vec3) for color needs to have its values decreased as the distance gets larger. Therefore to increase the intensity or distance of the light, the values of the constant, linear, and quadratic values are decreased. A good chart for some combinations to produce different levels of attenuation is located on Ogre3D's Wiki

After calculating the attenuation, the light's color is then scaled by the attenuation and added to the ambient light. This color is blended with the color of the objects in the environment creating an environment lit solely by the point light placed. Below is what I was able to produce with a single point light, and various colored platforms and objects.
White Light
Small White Light

Large White Light

Red Light

Blue Light

Yellow Light

No Lights(Full Color)
Currently I have not implemented shadow mapping so the lights do look off but this is a start that will lead to lights that look amazing.
I did run into a problem with Supernova Softworks' engine when trying to implement what I had learned, this problem was that the point lights seemed stretched when they should have been consistently circular. This was due to the fact that the point lights as well as the fragment positions were positioned in view port (NDC) space, causing the lights to change shape or position as the player moved around the screen.To solve this I discovered that I needed to pass a 4x4 matrix of the inverse of the world to NDC matrix to the shader program. Doing so I was able to temporarily transform the fragment position and the point light's position back into world space to ensure the calculations and fragment drawing was correct. After solving this problem I was able to create a point light with any position, color, and attenuation variables.

Timothey Goodwin
RTIS Student
General Programmer (Currently Specializing in Graphics)
DigiPen

Comments