The lights branch
I will be taking on the development of the fog of war a.k.a lights branch. The lights branch is built on top of PeterW's high resolution landscape shader which scales up the landscape x4. Its goal was to add dynamic lighting to the landscape rendering, which makes the landscape look even more stunning and three-dimensional. This also effectively adds fog of war to the game again since areas that are not lighted by the clonk appear as black.
The lights branch was originally developed by PeterW about three years ago. Unfortunately, work on it stopped over two years ago, so it can safely be declared as dead now. His original plans with this feature were quite aspiring. Global lighting by the sun and preliminary optimization seemed to have been the thing he ultimately failed on.
Rescueing the light branch
In my opinion, this project is too valuable and in a too advanced stage to give up, so my plan is to turn this into a team effort to "rescue" the work he has done so far into the master branch. I want to strive for a minimal solution here: No global light, no colored light, no multiple lights (lamps, torches). Just the current state minus the bugs and an option to turn if off, which it is by default.
Talking about aspiring, for me this is an utterly aspiring project. I am braced to try this project alone, but I'd love for that to be a team effort. Be it that you volunteer to get aboard this ship and help steer it back to master, be it that you can help with one task or even just give tips on how to solve the one or the other issue. In any case, I can use any help I get.
The plan
His work so far involves about 1500 lines of code, the very most being in C4FoW.cpp and a few lines in the shader itself. So actually, alone from the amount of code, this is perhaps not that of a big undertaking.
I plan to split the work in 3 phases:
1. understand, accustom, document and refactor the current code - with focus on phase 2
2. fix the known issues
3. implement the missing feature to reach a releasable state:
- add a scenario option AmbientLight = height1, height2. Only if it is defined, the shader should darken the landscape, otherwise 100% of the light is ambient light. The ambient light portion of the light dims down from height1 (100%) to height2 (0%).
- make fow affect objects as well
> 1. understand, accustom, document and refactor the current code - with focus on phase 2
- Currently trying to understand the structure. Put all the classes in C4FoW.cpp in own files (not committed yet)
Actually, a big part of the mentioned 1500 lines of code is pretty forward object oriented code that just needed a little bit of documentation to understand better. In a nutshell:
C4FoWRegion - Extension of the Viewport, renders the whole stuff to the screen
C4FoW - Keeps a list of lights (C4FoWLight)
C4FoWLight - Associated with one object. Has a size, and a section (C4FoWLightSection) for each direction
C4FoWLightSection - Keeps a list of beams and handles the mathematics
C4FoWRay - represents one beam
C4FoWLightSection then contains 1000 lines of the heavy mathematical stuff in spagetthi functions.
Most things on your list should be manageable, with the notable exception of "light applies to objects" (also particles, PXS, text, lines...?). That's probably going to touch a *lot* of code all over the engine. I consider it the main blocker to lights at this point.
I'm obviously available on IRC if there's questions (it's not exactly trivial code). If you plan to understand how I come up with the final mesh it might be a good idea to take a look at the sketches I made when coming up with it (attached). Note that the calculation of intermediate fade points (Y in the sketches) has changed quite a bit as I tried to come up with something that actually looks good.
> no multiple lights (lamps, torches).
And btw - that should work already. Just haven't tested it yet, so it might look bad in some way.
> - the brightness of "explored" areas does not reset to 0
By pure chance, found the bug. Fixed :-)
You sure you Pulled and Updated? Also, with which scenario for example do you have problems? I only tested in Tutorial01.ocs the last days.
// uncomment the following lines for debugging light directions:
// yellow: light up, blue: light down, turqoise: light right, pink: light left, opacity: light strength
float lightYDir = lightPx.b - 1.0/3.0;
float lightXDir = lightPx.g - 1.0/3.0;
float lightStrength = lightPx.r;
gl_FragColor = vec4(
1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
1.0-1.5*max(0.0, -lightYDir),
lightStrength);
* is the std::list considered harmful or something? I only see homebrew pointer-based lists in the (Peter's) code. I am in the process of replacing those with the std::list for proper OO but stopped because perhaps there a a good reason for not using the standard list?
* is there really no general simple point/coordinate class in the project yet? I feel dumb if I introduce something like that now.
> * is the std::list considered harmful or something? I only see homebrew pointer-based lists in the (Peter's) code. I am in the process of replacing those with the std::list for proper OO but stopped because perhaps there a a good reason for not using the standard list?
I've used it in new code as well. Just make sure that you don't introduce memory leaks or pointer errors because suddenly some pointers change when the objects are added to the list. Also make sure if classes are copied that this works. Stuff that breaks commonly if such assumptions are violated is e.g. loading of scenario sections (LoadScenarioSection()) or reloading of definitions (ReloadDef()).
And make sure stuff still works with StdCompiler. (For savegames, runtime joins, etc.).
But on the other hand I am the same guy that would also object to both using STL having anything to do with OO, or OO being that much of a good idea in the first place... Comes with the field, I suppose.
> The idea is to stay consistent, mainly. I find it neither particularly harder to write nor to read, so why not stay with it?
I don't really care for lists either. But once you need slightly more advanced stuff, like sorted lists or hash maps, you need to write a lot of boring code that is introduces potential bugs.
>an ambient light component
That would be awesome if you could busy yourself with that! It fits quite nice because that part has nothing to do with the actual light texture generation, more with the shaders.
The simplest solution would be to generate a 1D-8-bit-Array from the scenario options and put this as an uniform into the shader calculation. Do you aim for that?
> The simplest solution would be to generate a 1D-8-bit-Array from the scenario options and put this as an uniform into the shader calculation. Do you aim for that?
If all you have in mind is the two numbers mentioned in your initial post, then probably only those numbers are all that's needed in the shader. But I wonder whether there are better methods for example for scenarios like dark castle where there is a hill and basically you want everything bright outside the underground and dark when you go underground. So basically it would be nice to have some measure for how far a pixel is away from the sky, but I don't have a good idea yet how to calculate or approximate that.
Another question is how to combine the ambient part with the diffuse part of the light (for example you do want the ambient part to get darkened when light intensity is low, so that they disappear in the FoW, but you don't want them to be brightened when the light source is near, since at daylight the ambient part should dominate. This can probably be easily figured out with some experimentation.
> Another question is how to combine the ambient part with the diffuse part of the light (for example you do want the ambient part to get darkened when light intensity is low, so that they disappear in the FoW, but you don't want them to be brightened when the light source is near, since at daylight the ambient part should dominate. This can probably be easily figured out with some experimentation.
My initial suggestion was/is:
ambientLightStrength = 0..1
(depending on how deep you are/the px is)lightAtPositionFromLightmap = 0..1
lightAtPosition = ambientLightStrength + (1-ambientLightStrength) * lightAtPositionFromLightmap
The same with the direction of the light.
So, in daylight, you will see no effect from the lighting shader.
At the moment I tend to a solution where I would create a sort of "ambient light map", where the ambient light strength of each pixel would be determined by how many sky pixels are around it in a given radius. This would basically have to be computed only once at game start, since in a typical game the sky/tunnel (IFT) of pixels do not change. Also, it would probably be good enough if this light map was computed only for the unzoomed map, and then interpolated between pixels. This would have the advantage that the ambient lighting adapts itself to the landscape, and allows the scenario designer additional options (for example, put some small sky patches here and there in tunnels to get some extra light in). We could even allow custom ambient light maps (Ambient.bmp in addition to Map.bmp) for scenario designer who want full control of the ambient lighting themselves. What do you think?
This ambient light map could be of very low resolution, e.g. one px every 100 landscape px or so and then simply scaled to apply. E.g. you take a box of 100x100px of the landscape and the shade of grey the ambient light px for this box has is (number of sky px in this box / (100*100)).
> the simplest solution would be to generate a 1D-8-bit-Array
I'd say the simplest solution would be to just brighten up the light texture? If we flip around how the frame buffer gets updated we need to clear it anyway - we'd just use a fade then instead of solid (0,1/3,1/3). If we put the "scenario ambient map" ck proposed into a texture, this could just become a blit.
> I'd say the simplest solution would be to just brighten up the light texture?
The problem with this is that the light would then still have a direction, and faces of meshes pointing away from the light source would not be illuminated. This is one thing that I would want to fix with the ambient lighting, so that for example trees at daylight are not super dark on one side and super bright on the other, whereas at night, or underground, they would look much more like in the screenshots I have posted in the other thread. So basically I think it would be good to have the ambient and diffuse light strength separately from each other. Of course we could encode this information for example in the alpha channel of the light texture as well...
> If we put the "scenario ambient map" ck proposed into a texture, this could just become a blit.
Yes, I was thinking about that anyway, so that the landscape and object pixel shaders can access the ambient light at each individual pixel.
> Something like "intensity * (0.5 + dot product / 2)"?
Yeah, this is already similar to what Newton proposed... ambient + (1-ambient) * dot product
> I am not quite sure we would want the back sides of underground objects to be solid black either...
Indeed. We should be able to take care of this by generating the ambient map such that the lowest ambient value is never 0.0 but maybe 0.25 even in the darkest cave.
min(intensity, 1) * (ambient + (1-ambient) * max(intensity, 1) * dot(...))
such that the light intensity also affects the regions with ambient light. Now I understand your proposal would be to do
ambient + (1-ambient) * intensity * (0.5 + 0.5 * dot(...))
I suppose the difference would be that with the first option, sky would only be visible when in light of sight of the clonk, while with the second one, sky (and the edges to material) would always be visible. Yeah, I actually might like the second option more...
(intensity + ambient) * (0.5 + 0.5 * dot(...))
No idea, we'll have to see what looks good. I'd just be reluctant to involve yet another texture unit or uniform for an effect that is just a variant of what we have already.
Worrying about the number of uniforms or texture units at the moment seems a bit like premature optimization to me at this stage. If these turn out to be an issue, we can still think about optimizations later.
But this is really something for when the lights branch is merged into master IMO. Lets really do the shortest route to master here.
> ambient light component
I have committed something into the lights branch. The ambient map is generated from the landscape, and then used as an additional texture unit in the shaders. The effect is that every sky portion and what is close to it (the fade radius is 50 pixels at the moment) is visible, and only underground areas are covered with FoW.
The ambient light intensity is not just added to the intensity of the light texture, so that the ambient light and the light from other light sources can have different directions. For example, when a tree is on the surface, it is illuminated somewhat uniform, while if it is underground, it is illuminated from the direction of the light source. For meshes and the landscape, I did not actually use a fully ambient light in the sense that it is completely independent from the normal vectors, since this makes everything on the surface look very "flat", for example the gold idol does not even have a texture and would appear with only a single color. Instead, the light direction is fixed to "from the front" (meshes) or "from the top" (landscape), which corresponds to the same behaviour as in the master branch for stuff that is not underground. Things can certainly be tweaked more here!
The ambient light texture you generate, is that a 1:1 32bit texture for the whole map?
> Wow, very cool! Very cool. This looks so good already that I'd like to suggest to move on to the other things that block the merge to master first before tweaking around some more.
Thanks ;) -- Do you consider everything in the "issues" topic to be a blocker?
> The ambient light texture you generate, is that a 1:1 32bit texture for the whole map?
It is 1:10, and it only has one color channel (red), representing the ambient intensity. I don't know 100% how OpenGL internally stores it, but I think it is 8 bits per channel, and therefore 8 bits per pixel.
Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill