Yakiimo3D

Mostly DirectX 11 Programming

DX11 DirectCompute Global Operator Photographic Tonemapping

Introduction

I wrote a DX11 DirectCompute implementation of the famous global operator photographic tonemapping algorithm developed by Erik Reinhard, Mike Stark, Peter Shirley and Jim Ferwerda. My code is based on the original code provided by the authors at http://www.cs.utah.edu/~reinhard/cdrom/. As in the sample source, my implementation performs tonemapping on luminance values in the Yxy color space. The DirectCompute portion of my source code is heavily based on the HDRToneMappingCS11 sample provided in the DirectX SDK.

Relevant Links

1) http://www.cs.utah.edu/~reinhard/cdrom/
Eric Rheinhard’s homepage for the photographic tonemapping algorithm. The homepage contains links for the paper “Photographic Tone Reproduction for Digital Images”, sample source code and HDR images in .hdr format.

2) http://wiki.gamedev.net/index.php/D3DBook:High-Dynamic_Range_Rendering
The free DirectX10 programming book “Programming Vertex, Geometry, and Pixel Shaders” hosted by gamedev.net contains a chapter on HDR rendering that includes an explanation and implementation of Rheinhard tonemapping. The chapter is written by ex-Rockstar Games graphics programmer and GPU Pro (used to be called ShaderX) book series editor Wolfgang Engel (http://diaryofagraphicsprogrammer.blogspot.com/) and it’s really good.

3) http://www.gamedev.net/community/forums/topic.asp?topic_id=407348
gamedev.net forum discussion on implementing the Rheinhard tonemapping operator.

4) http://www.t-pot.com/program/123_ToneMapping/index.html
t-pot.com’s DX9 implementation of the Rheinhard global tonemapping operator. Tonemapping calculations are performed on luminance values in YCrCb color space.

Demo Pictures

HDR Cornell Box

Cornell Box No TonemappingCornell Box With Tonemapping

Comments

The left image is an HDR Cornell box render image without tonemapping. The right image is the same image with tonemapping enabled. Without tonemapping, the HDR values all get cut off at 1, resulting in bright washed-out areas. With Rheinhard tonemapping enabled, the HDR image gets re-mapped better to an LDR range and colors in the bright HDR sections of the image are visible.

LDR Cornell Box

LDR Cornell Box BurnOut Control EnabledLDR Cornell Box BurnOut Control Disabled

Comments

The above is a test of what happens when you tonemap an LDR (max luminance less than 1) image. The right image has the maximum luminance burnout control disabled. The left image has the maximum luminance burnout control enabled. Notice that the left image is brighter with greater contrast. When the maximum luminance burnout control is enabled, the resulting tonemapped values are not forced to burnout into 1 (they can exceed 1 and simply get clamped to LDR during the framebuffer write) and a stronger contrast can be brought out.

HDR Outdoors Scene

HDR Outdoors Scene No TonemappingHDR Outdoors Scene With TonemappingHDR Outdoors Scene Without Tonemapping Burnout Control

Comments

The left image is an HDR outdoors scene without tonemapping. The middle image is the same image with tonemapping enabled. The right image is the same image with tonemapping enabled but burnout control disabled. Unlike with LDR images, the effect of the (1+L(x,y)/L_{white}^{2}) burnout control is not very strong in HDR images when the maximum luminance is used for the L_{white} value.

The above HDR images were obtained from http://www.cs.utah.edu/~reinhard/cdrom/hdr.html.

Implementation Details

1) Compute Shaders Log Average Luminance & Max Luminance Calc Step

\bar{L}_{w}=exp(\frac{1}{N}\sum_{x,y}^{}log(\delta+L_w(x,y)))

The above is the equation for calculating the log average luminance of the scene. In Rheinhard’s tonemapping paper, it’s regarded as an approximation to the scene’s key. In DX9, this value is calculated in the pixel shader by downsampling into a 1×1 texture. In my DX11 implementation, the log average luminance is calculated in the compute shader. In addition to the log average luminance, the maximum luminance of the scene is calculated as well. In my demo, this computation is performed in the same fashion as the HDRToneMappingCS11 sample provided in the DirectX SDK. Each thread group in the ReduceTo1DCS.hlsl compute shader outputs its log average luminance and the maximum luminance into a single texel in a 1D texture. Then this 1D texture is processed multiple times in a different compute shader at 128 thread threadgroup chunks until a single log average luminance and the maximum luminance value remains.

2) Pixel Shader Tonemapping Step

L(x,y)=\frac{a}{\bar{L}_w}L_w(x,y)

In the tonemapping pixel shader, using the above equation, luminance values are adjusted so that the log average luminance is mapped to the middle-grey value.

L_d(x,y)=\frac{L(x,y)(1+\frac{L(x,y)}{L^{2}_{white}})}{1+L(x,y)}

Then this adjusted luminance is scaled to a LDR displayable range using the above equation. This last equation has the characteristic that high luminance values are compressed more than the lower luminance values. L_{white} value is set to the maximum luminance calculated in the compute shader. The tonemapping paper says that using this maximum luminance adjustment increases contrast for LDR (max luminance < 1) images (look at the Figure 6 graph plots in the paper to be convinced.)

Demo

Input HDR images are assumed to be in linear space and all tonemapping calculations are done in linear space. No pixel shader gamma correction is performed during write because an SRGB framebuffer is used.

Source Code & Binary
http://yakiimo3d.codeplex.com/releases/view/41919

The HDR images included in the demo were obtained from http://www.cs.utah.edu/~reinhard/cdrom/hdr.html. Since D3DX11CreateTextureFromFile is unable to handle .hdr files (looks like the DX9 equivalent handled .hdr file types), I used the DirectX Texture Tool included in the DirectX SDK to convert the .hdr files into .dds files. The DirectX Texture Tool was unable to load some of the sample .hdr files. For those files, I opened and re-save them as .hdr files using the nice, free http://www.hdrlabs.com/picturenaut/. After they are re-saved using Picturenaut, I was able to load the .hdr files into the DirectX Texture Tool.

Concluding Words

Man, spent a lot of my weekend writing this blog post. Think I’m going to work on the Japanese translation during the weekday. Going to finishing my weekend by grabbing dinner and playing a little bit more of Battlefield Bad Company 2 (which has been a lot of fun so far.)

. This entry was posted on Saturday, March 13th, 2010 at 11:54 PM and is filed under Demo, DirectCompute, DirectX11. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

2 Responses to “DX11 DirectCompute Global Operator Photographic Tonemapping”

  1. List of Direct3D demos « tse: Says:

    [...] Global Operator Photographic Tonemapping (yakiimo02) – Compute Shader 5.0 [...]

  2. DX11 DirectCompute Buddhabrot & Nebulabrot | Yakiimo3D Says:

    [...] DX11 DirectCompute Global Operator Photographic Tonemapping [...]

Leave a Reply



XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

It may take some time for your comment to appear, it is not necessary to submit it again.