Welcome everybody!
Last time I made something for outlook of my game. Previously I was able to darken environment via manually setting color per each vertex, now besides that, I can also specify global ambient color which is darkening level. Furthermore, it is possible to attach light spot to any object on scene, then every objects that are in certain radius from light are illuminated. Additionally, I implemented shadow casting algorithm basing on this article. But let’s start from the beginning, general recipe for that effect looks pretty simple:
1. Clear screen with ambient color
2. For each light
a) set drawing only to alpha channel
b) remove existing on screen alpha channel
c) set blending to additive
d) for each object near light: render shadow using only alpha color
e) set drawing only to r g b channels
f) render light only where, there is no shadow
3. copy light-map existing on screen to texture
4. clear screen
5. draw scene normally
6. set multiplicative blending ( wherever light-map is black there will be dark)
7. draw quad with dimensions of screen textured with light-map
8. bonus: if emissive light needed draw it again with additive blending
Re 2.f
just draw quad with light gradient texture like image on right, you may also change light color by glColor…
Re 1, 2.b and 4
in opengl we can clear screen by using glClear(GL_COLOR_BUFFER_BIT) function as long in this case we aren’t using depth and stencil buffers. Additionally we can set global ambient color via glClearColor(ambientR,ambientG,ambientB,0.f); so it will immediately fill screen with wanted color
Re 2.a 2.e
setting true or false in parameters enables or disables drawing to that channel glColorMask(red,green,blue,alpha); Re 3 we can copy pixels to texture by using glCopyTexSubImage2D function or… we can skip this point if we previously set rendering directly to texture via FrameBufferObjects (FBO) then we can avoid copping pixels from screen to texture. It seems to be large optimization, In by case glCopyTexSubImage2D works faster than FBO and everywhere people are writing that it should be slower. I don’t know why this is so. I suspect that it can be because my old integrated graphics card (intel GMA X3100)
Re 2.c 2.f and 6
blend function so the way how existing color of pixel and currently drawing is mixed we can set by glBlendFunc(enum ,enum) it is still bit confusing to me but I understood couple of setups
- multiplicative: previous color * actual color = glBlendFunc(GL_DST_COLOR, GL_ZERO)
- additive: previous color + actual color = glBlendFunc(GL_ONE, GL_ONE)
- drawing inversely proportional to amount of alpha = glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE)
Note: this lighting system was done without any shaders, only pure OpenGL with fixed pipeline. The essence is to know how to generate light texture and using appropriate blending functions
2.d is most complicated step. It consist in drawing shadows only with alpha set to 1.0. Firstly my must find all overlapping objects with light, I have done that by comparing axis aligned bounding boxes. Then for each vertex in found object we must calculate vector from light, next we perform dot product on it and object edge normal to determine if this vertex is necessary to cast shadow. After that, draw each found vertex and vertex casted outside light. As performance optimization we can set glScissor test to save some fill rate.