I have finally implemented automatic exposure by downsampling the scene recursively until i get a 1x1 pixel that contains the scene luminance. I have two implementations: a simple average, and Reinhard's operator. The first one is fast and looks pretty good. The second one is supposedly more accurate, but requires more pixel shader instructions, and at the moment its advantages are not clear compared to a simple average. Needs more experimentation.
Once the scene luminance is stored in a 1x1 texture, i interpolate this texture with the "current" luminance. This makes the luminosity adapt over a short period of time ( currently set at one second ), rather than being instantaneous. If you go in a dark area and quickly look at the sky, everything glows. It's magic !
Speaking of glows, i am now downsampling and blurring the scene multiple times ( previously, i was doing it only once, meaning the pixels range the bloom could affect was limited ). Doesn't cost too much performance. I'm also performing the blur in a standard, fixed point RGBA 8 bits texture, instead of using a FP16 buffer. It's faster, and i can make use of bilinear filtering to have an even better blur. The downside is that the values are clamped to [0-1], but it's possible to work around this "problem" by playing with the parameters.
In one of my previous journal entries ( 6 months ago ? ) i was speaking of assigning a shadow map for each object. I dropped this technique in favor of cascaded shadow maps. It seems like cascaded shadow maps offer the best performance/quality trade off. At the moment, i'm using 2 levels of shadow maps ( each 2048^2 ), but i'm planning to add more once everything feels "right".
In order to get good transitions between the two shadow maps, i had to implement.. orthographic projections. Previously, i was using a perspective frustum with an apex set very far away ( to reduce the distortions due to perspective ) and a very big near clipping plane distance. Because there was two different shadow maps each with their own frustum, the perspective distortion prevented the shadows of one map from matching with the other one. Disturbing.
Now, with orthographic frustums, everything is good. I spent my whole week end on this implementation, mostly lost in debugging, since i forgot the fact that my matrices were setup in the DirectX way rather than the OpenGL way ( which i'm using for rendering ). Of course, checking the ortho projection matrix and comparing it to the one built in OpenGL, i did not find any difference.. except that it was expecting the ortho matrix the way it's built in DirectX. Ah Ah.
The two shadow maps are centered on the camera and are moving with it. It causes the shadows to flicker. I fixed that by transforming the shadow maps origin into object space, round this position to the shadow map texel size, and transform it back to world space. No more flickering. Except when the light itself moves, but there's nothing i can really do to help.
Shadow maps ( actually, the closest level only ) are antialiased - not really "soft" shadows, but the effect is cool. On NVidia cards, it's very nice, thanks to hardware PCF. On ATI cards it's less nice, even sampling the shadow map 8 times. The performance hit is... important.
I still have to improve shadows in the future. One thing i want to try is to store the shadow maps in an "atlas" texture, a single 2048^2 that will contain 4 1024^2 shadow maps. Four levels of shadow maps, even at half the resolution, might look better than what i currently have on two levels. It should also allow me to antialias all the levels. It should be lighter on memory and performance, since there's no need to render to 4 separate textures; only adjust some texture coordinates in a shader to write to or read from a specific quarter area, and it's done. Or, at least, i hope so..
Shadow maps are not updated every frame, but only every 4 or 8 frames ( respectively, for the two levels of shadow maps i currently have ). The largest shadow map is just enough to cover the whole city ( see video ).
On LOD ( level-of-detail ):
I spent a few days improving the current metrics. Nothing really important to say, it's very technical and mostly related to debugging and understanding why, sometimes, some silhouette edges are moved.
Disclaimer: keep in mind this is a work in progress. Yes, it's not perfect. There are tons of little problems, parameters to adjust. Things will improve over time. And keep in mind it's yet another "tech" demo: even if it looks nice, it's far, extremely far from being more than a rendering prototype.
City video ( 45.8 MB, Divx5 ) : showing off the city and a few models. Stannum's buildings, Shawn's city dome ( a draft - yeah, textures are really deformed, it will be fixed. Same for the "metallic grid" on the roof ), CutterJohn's Intrepid, and 100 Shadix/Petrov interceptor's loaded ( to have any idea of the slowdown due to traffic ). Also shows HDRI and dynamic shadows.
Spuk's outpost : showing off the small station made by Spuk. Generic textures, no skybox/background, it's a bit plain, but it shows HDRI + dynamic shadows. Interior not shown due to backface culling problems in the model.