Advertisement

Tone Mapping

Started by October 12, 2017 12:57 PM
52 comments, last by MJP 7 years, 3 months ago
56 minutes ago, turanszkij said:

Oh, that is actually useful then. I didn't care so much for performance implcations of gamma conversion yet, but this is a really useful feature. My other concern with the SRGB texture format was this (from MSDN):

If the driver type is set to D3D_DRIVER_TYPE_HARDWARE, the feature level is set to less than or equal to D3D_FEATURE_LEVEL_9_3, and the pixel format of the render target is set to DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, or DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, the display device performs the blend in standard RGB (sRGB) space and not in linear space. However, if the feature level is set to greater than D3D_FEATURE_LEVEL_9_3, the display device performs the blend in linear space, which is ideal.

I don't intend to support DirectX 9 feature level, but nevertheless this just seems to me that proper support for this format is not 100% guaranteed.

Right, this was how older D3D9-era hardware behaved. However if you're going to try to support that level of hardware, then I think your sRGB blending behavior is probably the least of your concerns. :)

"Fun" fact: when D3D10 hardware came out that implemented the proper blending behavior for sRGB render targets, that new behavior was applied even to existing, shipped D3D9 games! So if you play Half Life 2 on an Nvidia GeForce 7800 and then play it on a 8800, it actually looks a little bit different  in places where alpha blending is used!

27 minutes ago, matt77hias said:

This makes sRGB formats useless for resources that must be read, unless you use a point sampler (so basically one texel access and no filtering). So the base color buffer of the GBuffer can benefit from an sRGB format.

I think that you misunderstood me: filtering and blending is fine with sRGB formats. It's not fine if you manually apply the transfer function and inverse transfer function in the shader. Sorry if that wasn't clear from my post.

Ok I misunderstood the filtering (thought you implied the opposite). But should one then always use sRGB for color data which is not point sampled (sprites, base color textures, etc.)?

🧙

Advertisement

You definitely should if the source data would benefit from being stored using perceptually-weighted curve, which is often the case for "color" data. The sRGB transfer curve will skew the precision distribution of your fixed-point storage such that more bits are used for the darker side of the [0, 1] range. This maps well to the human visual system, where the logarithmic response of our eye receptors means that we perceive a larger brightness increase when going from 0.01 -> 0.02 then we do when going from 0.98->0.99. So in that regard, you can think of the sRGB transfer curve as being sort of a compression function, which when used gives you a better precision distribution when using fixed-point storage. Note that this sort of logic doesn't necessarily apply to floating-point formats, which inherently have a exponential distribution of precision!

TL:DR definitely use it color data stored in fixed-point or block-compressed texture formats. It will give you better quality with no performance disadvantage.

 

34 minutes ago, MJP said:

You definitely should if the source data would benefit from being stored using perceptually-weighted curve, which is often the case for "color" data. The sRGB transfer curve will skew the precision distribution of your fixed-point storage such that more bits are used for the darker side of the [0, 1] range. This maps well to the human visual system, where the logarithmic response of our eye receptors means that we perceive a larger brightness increase when going from 0.01 -> 0.02 then we do when going from 0.98->0.99. So in that regard, you can think of the sRGB transfer curve as being sort of a compression function, which when used gives you a better precision distribution when using fixed-point storage. Note that this sort of logic doesn't necessarily apply to floating-point formats, which inherently have a exponential distribution of precision!

TL:DR definitely use it color data stored in fixed-point or block-compressed texture formats. It will give you better quality with no performance disadvantage.

 

That's nice in theory, unfortunately the final brightness your textures end up as onscreen are only somewhat correlated to their albedo in the stored texture. IE a bright near white texture can end up darker than a fairly dark texture if the white one is in darkness and the dark one brightly lit in the actual environment (assuming a large hdr range). Thus you'd end up with banding on the near white texture while the brightly lit dark texture gets no benefit from the perceptual compression.

I'd just stick with srgb for final tonemapping and final perception, instead of source data.

11 hours ago, MJP said:

You definitely should if the source data would benefit from being stored using perceptually-weighted curve, which is often the case for "color" data. The sRGB transfer curve will skew the precision distribution of your fixed-point storage such that more bits are used for the darker side of the [0, 1] range. This maps well to the human visual system, where the logarithmic response of our eye receptors means that we perceive a larger brightness increase when going from 0.01 -> 0.02 then we do when going from 0.98->0.99. So in that regard, you can think of the sRGB transfer curve as being sort of a compression function, which when used gives you a better precision distribution when using fixed-point storage. Note that this sort of logic doesn't necessarily apply to floating-point formats, which inherently have a exponential distribution of precision!

TL:DR definitely use it color data stored in fixed-point or block-compressed texture formats. It will give you better quality with no performance disadvantage.

Currently, my color data is not stored with an explicit sRGB format though the data represents non-linear colors. I do the conversions manually, but I understand that like you said, you (could) run into trouble for filtering. But this imposes a problem, I think:

How could you customize this? The overall approximate gamma of sRGB is 2.2?

 1hyk01akYAoDc-meLZjd5jb0UDSS11tvYPJmE_OiYQg.jpg.12ad9421a5ac301f6f4c6667b70d006d.jpg

10 hours ago, FreneticPonE said:

I'd just stick with srgb for final tonemapping and final perception, instead of source data.

Assuming you use some block compression for your source data, your source data consists of non-linear colors? 1 uncompressed byte/channel for linear colors has not enough precision.

🧙

11 hours ago, FreneticPonE said:

Thus you'd end up with banding on the near white texture while the brightly lit dark texture gets no benefit from the perceptual compression.

 This isn't true. The data in your source textures is almost certainly gamma2.2/sRGB data, assuming it was painted by an artist on a regular monitor. Doing any math on that texture data without first decoding from gamma2.2/sRGB is simply wrong, which results in overblown contrast, colour banding, hue shifts, softened lighting gradients and overblown highlights when multiple lights overlap.

Decoding your source textures is a vital part of having a 'gamma correct' renderer. And if you're encoding your outputs but not decoding your inputs, you'll likely have a lot of colour banding too! 

On the other hand, if your source textures somehow don't contain gamma2.2/sRGB data, you'll be guaranteed to suffer from colour banding as 8 bits with a linear encoding is nowhere near enough to cover human perception. 

Advertisement
1 hour ago, matt77hias said:

But this imposes a problem, I think:

How could you customize this? The overall approximate gamma of sRGB is 2.2?

 

Gamma2.2 is a good approximation for sRGB if you're implementing if yourself. It only really differs very closely to black. 

You don't need to customise the decoding of your source data if you assume that all your artists are working on SRGB monitors. 

You may want to support customisable final encoding / output gamma to be nice to users with badly calibrated / non-standard monitors. For that, you can use a non-sRGB texture format for your backbuffer and instead use a customisable pow curve at the end of your tone mapping shader (which converts from high precision linear to 8/10bit backbuffer). 

5 minutes ago, Hodgman said:

You may want to support customisable final encoding / output gamma to be nice to users with badly calibrated / non-standard monitors. For that, you can use a non-sRGB texture format for your backbuffer and instead use a customisable pow curve at the end of your tone mapping shader (which converts from high precision linear to 8/10bit backbuffer). 

Thanks that was what I was looking for :) Custom gamma correction postponing till writing to the back buffer. At a second thought the intermediately used gamma does not influence the end result (except for the wrong conversion after filtering), since encoding is always undone by decoding.

🧙

Converted my formats to sRGB (though they do not originate from sRGB, since otherwise they seem way to dark):

Clipboard01.png.a3acd33ca45d8245948db553f2f8a18c.png

Originally, I always did the gamma encoding/decoding manually:Example.png.cc63384a8f196765129fc29e33b50ab5.png

P.S.: changed my sky since all my skies were already compressed :(

 

🧙

12 hours ago, Hodgman said:

 This isn't true. The data in your source textures is almost certainly gamma2.2/sRGB data, assuming it was painted by an artist on a regular monitor. Doing any math on that texture data without first decoding from gamma2.2/sRGB is simply wrong, which results in overblown contrast, colour banding, hue shifts, softened lighting gradients and overblown highlights when multiple lights overlap.

Decoding your source textures is a vital part of having a 'gamma correct' renderer. And if you're encoding your outputs but not decoding your inputs, you'll likely have a lot of colour banding too! 

On the other hand, if your source textures somehow don't contain gamma2.2/sRGB data, you'll be guaranteed to suffer from colour banding as 8 bits with a linear encoding is nowhere near enough to cover human perception. 

This is the idea I know. But suddenly I'm questioning it because you aren't displaying the actual srgb texture by itself as the final image. You're doing any number of things to it before finally displaying, thus while your input is correctly compressed for human perception your output might not be. 

This topic is closed to new replies.

Advertisement