Put into a VBO each polygon's edge (such as sides of walls that block light) as a vec3
quad [0]. 2 vertexes must be (x, y, 0) of the edges, 2 other vertexes must be the same vertexes but as (x, y, 1) that will get projected into infinity in the shader (below). Only do that once before drawing all lights. The shader will figure out where to project into infinity for each light separately, with the same VBO contents.
Add a framebuffer without depth, but with 2 RGBA8 color attachments (temporary and accumulator).
Add a new shader with 2 color attachment outputs (for temporary and accumulator) and a few uniforms, including int
mode (values 0, 1, 2).
You draw using modes in order: 1, 0, 2.
Clear both color attachments using black.
Bind the framebuffer.
Call glBlendFunci(0, GL_ONE, GL_ZERO)
.
Call glBlendFunci(1, GL_ONE, GL_ONE)
. This allows blending temporary into accumulator.
Bind the texture of temporary as a sampler and pass it as the sampler0 uniform.
Now, call glNamedFramebufferDrawBuffer(framebuffer_id, 1, &{0, GL_COLOR_ATTACHMENT0}
.
Bind the texture of temporary to the sampler0 uniform (see below)
In vertex shader:
Get position as vec3
. Do vec2 pos=position.xy.
If mode is 0, do [U]pos[/U] += (position - light_center.xy)*[U]position[/U].z*1e4
. [1]
Then output gl_Position = vec4(pos, 0, 1).
In fragment/pixel shader:
Add a sampler2D
called sampler0.
You have 2 vec4
outputs, color0 and color1.
If mode is 0, output all black (or all white if you're debugging this mode) to color0 using VBO I mentioned earlier.
If mode is 1, draw a fullscreen quad, in the shader get light range as float
in pixels and compute distance between light center [2] and the pixel coordinate gl_FragCoord.xy
. You can now compute the light's final color using the distance and your light parameters (center in world coordinate space, range, color, etc.). Again, output to color0.
For mode 2, Call glNamedFramebufferDrawBuffer(framebuffer_id, 1, &{1, GL_COLOR_ATTACHMENT1})
, then draw a fullscreen quad.
[0] In world coordinates scaled to clip coordinate space.
[1] In clip coordinates, aka the entire screen between -1 and 1.
[2] In window-relative coordinates, aka what gl_FragCoord
uses.
[3] You can do with just 1 output but it's less clear.