Saturday, November 21, 2015

Light and magic

Using FBOs, multitexturing, different blending modes and few simple shaders I managed to make very simple lighting system. I think the end results look pretty good:

No light

Example 1 - blue tint

Example 2 - orange tint

What were the requirements:
a) sprites in a layer should be illuminated with light of different colors
- front layers should block the light from the back 
b) light should "bleed" over the edges of front layers (eg. solid walls)
- not affect back layers that are in distance (eg. sky)
c) different layers should be able to be illuminated seperatelly
d) layers should also be able to get darker

a) To illuminate sprites in a certain layer using some color I render them on a black FBO using a shader that colors the pixels of the sprite's texture in a set color. Then I can render that FBO over the final scene using (GL_DST_COLOR,GL_ONE) blend mode and color the sprites. But, not so fast.

After the sprites that will be illuminated are rendered on the light FBO in color,  I also render the front layers that should block that light in black to cover up those pixels. In the examples above the outside light should be blocked by the ground and the building on the left, the light from the building should be blocked by the building walls and ground.

b) Notice how the edges of the darker front sprites are also colored. To get the "bleeding" effect I blur the light FBO, so the light expands a bit:

To know which layers the blurred light should affect and which not, I need a FBO which serves as a mask. On that FBO I render all the sprites on which the final blurred light can fall, and using multitexturing and a shader I only render the pixels from the light FBO where the pixel is "on" on the mask FBO. Since the "sky" is not rendered on the mask, it wont be affected by the light, but, like seen above, it affects the front layers, which were rendered on the mask.

Mask FBO - green means light should be rendered there

 The sky didn't turn blue, but the wall on the bottom-left did

c) As you can see on the first images the outside area and the area inside the building on the left are illuminated differently. I can use the technique above on as many layers I want, then take the light FBO of the certain layer and render it all on the final light FBO using (GL_SRC_ALPHA,GL_ONE) blend mode to get alpha blending, then I can finally render that light FBO over the final scene using (GL_DST_COLOR,GL_ONE) blend mode.

Final light FBO is a mix of 2 FBOs

d) To darken certain layers(ground and building walls on the images above) I can take the above light FBO and render it over the scene using a mask where I previously rendered all the layers/sprites that should be darken up. Then I render the "dark" pixels where the pixel of the mask FBO is "on". Since the light FBO was already blurred and stuff, I get a nice fade to black at the edges, by using the RGB color values of the light FBO pixels to determine alpha value for the final dark pixel. Here the (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) blend mode is used.

No comments:

Post a Comment