3
\$\begingroup\$

I am writing a game using SharpDX with DirectX11 and I have been reading that it is important to apply gamma correction to my engine in order to perform correct linear lighting calculations.

So I modified the function which loads my diffuse texture maps so that it uses R8G8B8A8_UNorm_SRgb format rather than R8G8B8A8_UNorm. I then modified my framebuffer format so that it also uses R8G8B8A8_UNorm_SRgb.

It was my understanding that this would use hardware to remove gamma correction from my textures allowing me to perform linear lighting calculations and then reapply gamma correction when rendering the final scene to the frame buffer.

However when I do this the scene looks washed out and too bright. My next step was to take a look at some gamma calibration charts Gamma Calibration Chart. When viewing this chart in my browser I get a value of approximately 2.2.

I then loaded this chart into my engine and rendered it to screen. When using R8G8B8A8_UNorm I get the same value (approximately 2.2) but when using R8G8B8A8_UNorm_SRgb I get a value around 1.2.

It seems like the scene has already been gamma corrected somehow. Is this the case, what am I missing?

\$\endgroup\$
5
  • \$\begingroup\$ Do you have any lighting in your scene? If you do, the light colors likely need to be converted to linear space as well. A useful test is to temporarily disable lighting and just render the textures directly to the framebuffer without doing any math on them. They should appear the same with or without the _SRGB formats, since the gamma correction is being done and then undone. \$\endgroup\$ Commented May 30, 2013 at 21:42
  • \$\begingroup\$ It's also worth noting that the gamma calibration chart cannot be filtered at all or it's likely to be completely screwed up, so ensure you're viewing it with nearest-neighbor sampling in your engine. \$\endgroup\$ Commented May 30, 2013 at 21:51
  • \$\begingroup\$ The lighting is not applied to the gamma chart and I am sampling using MinMagMipPoint with min/max 0 mip lod. Also, the chart appears correctly for non-sRGB format. \$\endgroup\$ Commented May 30, 2013 at 21:57
  • 1
    \$\begingroup\$ Current hardware should implement srgb conversion before doing texture filtering and thus should not have any problems with texture filtering. It sounds like the sRGB framebuffer works fine but texture filtering does not do the sRGB conversion. Does not using sRGB for the diffuse texture have any changes on the output? Does applying pow(sample, 2.2) in shader instead of using the sRGB format result in a similar output? \$\endgroup\$
    – Archy
    Commented May 31, 2013 at 0:25
  • \$\begingroup\$ @Archy - you were correct, I was not removing gamma correction from my textures - see my answer below. \$\endgroup\$ Commented May 31, 2013 at 15:42

1 Answer 1

2
\$\begingroup\$

As suggested by Archy, sRGB conversion was not being applied to my texture maps.

The problem was that I missed a flag from the ImageLoadInformation used to load my diffuse texture maps. This meant that gamma correction was not being removed from my source textures before lighting was applied, leading to double gamma correction on output to the frame buffer.

return (Texture2D)Texture2D.FromFile(
    DeviceManager.Instance.Device,
    filename,
    new ImageLoadInformation
    {
        Format = Format.R8G8B8A8_UNorm_SRgb,
        Filter = FilterFlags.SRgbIn | FilterFlags.None,
        BindFlags = BindFlags.ShaderResource,
        CpuAccessFlags = CpuAccessFlags.None,
        Usage = ResourceUsage.Default
    });

I was missing

Filter = FilterFlags.SRgbIn
\$\endgroup\$
6
  • \$\begingroup\$ Good you got it working, but I think your explanation might be backwards - if I understand correctly, FilterFlags.SRgbIn causes the texture loader to assume the texture is already in sRGB format. Without it, it was probably assuming the texture was linear and converting to sRGB on load; then the texture sampler in the shader would undo that conversion, giving you the original texture data (sRGB) in the shader, where linear data was desired. \$\endgroup\$ Commented May 31, 2013 at 16:23
  • \$\begingroup\$ I am more confused now than ever! So do I want to use sRGB format and FilterFlags.None? On a related note, I am now suffering from serious quantization in dark colours, there are bands of colour to do with the way that rgb colour is corrected on output. \$\endgroup\$ Commented Jun 1, 2013 at 16:54
  • \$\begingroup\$ You want to use sRGB format, and whatever flag combination causes the texture loader to leave your texture well enough alone when loading it. I'm not an expert on SharpDX so you'll need to consult the docs (and maybe run some experiments) to determine this. \$\endgroup\$ Commented Jun 1, 2013 at 18:56
  • 1
    \$\begingroup\$ And the quantization in the dark colors is probably a sign of something being converted from sRGB to linear and then stored in an RGBA8 texture or buffer, then converted back to sRGB at some point. Linear color space requires more than 8 bits of precision (which is one reason why we store textures in sRGB space to begin with). \$\endgroup\$ Commented Jun 1, 2013 at 18:58
  • \$\begingroup\$ Ahh of course, so I need to upgrade my deferred shader's gbuffer to greater precision if I want to work in linear colour space. I was considering looking at HDR lighting next anyway so moving to R16G16B16A16_FLOAT is probably to only way forward. Thanks for your help! \$\endgroup\$ Commented Jun 1, 2013 at 19:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .