I have been experimenting with tone mapping from a long time. I tried many different ways of implementing tonemapping & bloom and now I have finalized this feature in the engine.
Tone mapping is a technique used in image processing and computer graphics to map one set of colors to another to approximate the appearance of high dynamic range images in a medium that has a more limited dynamic range.
I tried few different Global tone mapping operators with various ways to calculate scene luminance.I tried 3 major approaches (with a lot of variations in between) –
In the first approach, I calculated scene luminance by averaging log luminance values of HDR render target of the scene. I did this by rendering a screen space quad calculating log luminance values for the scene and then I used GenerateMips to average them automatically for me. I tried some different tone mapping operators including Reinhard, filmic curve and modified filmic curve (or uncharted2’s filmic curve). At the end modified filmic curve with the ability to modify the curve as need turned out to be the best approach for tone mapping operator.Problem with this method is any few extreme dark/bright spots in the scene can make the whole scene look brighter or darker beyond desired ranges.
I worked on a basic naive implementation of HDR rendering few months back using old DX9 style pixel shaders. Actually I have a lot of old experimental shaders created in Nvidia FX Composer long back (tone-mapping, physically based BRDFs, etc) and I integrate them to the engine as required providing backend support in c++ code and improve on them as necessary using Direct3d11 features. So that old pixel shader based ToneMapping shader was one such example. It was not so great either in quality or the performance but not so bad for first implementation. Here are the rendering stages involved in that implementation : –
As a part of task to make a physically based rendering pipeline I am working on HDR rendering nowadays. The motivation behind HDR rendering is that normal RenderTargets and the display devices have R8G8B8A8 format and we can only use individual colors from 0.0f – 1.0f floating point range which is very limited specially if you want to model real work lighting & shading because values easily go past 1.0f and we need more precision more bits per channel. So we use one of the HDR rendet targets R16G16b16A16 , etc. But display devices still can only display 8 bits per channel so we have to map those 16bit per channel back to 8 bit per channel for which we use ToneMapping.
Normally the term HDR rendering is referred to a group of effects including rendering things to HDR render target, Tone-mapping, Bloom, Eye Adaptation, etc. And I have finished my first basic implementation including couple of those effects using pixel shaders . I am sing R16G16B16A16 render target. For luminance I am averaging scene luminance by downscaling the scene luminance render target and then using Erik Reinhard’s method for Tone-mapping. Also implemented a bright-pass filter followed by Gaussian blur for Bloom.
So this is first very naive implementation. There are some bugs, I am working on itand also some more experiments with some different techniques. I am also thinking to try it using compute shader.
Here’s a Scene Rendered to HDR render target –
And after final pass with Tone-mapping –
And here are the views of 3 different areas keeping all settings same and also shown all the passes that are combined to produce the final image ( check how the floor shade changes depending on the total illumination of the scene ). –