Advertisement

Image Loader Color Space

Started by June 18, 2019 01:36 PM
5 comments, last by deadc0deh 5 years, 7 months ago

Howdy,

I have been upgrading texture support in my framework, I opted to use stb_image instead of individual libs (except for lib tiff) however, I have no idea how to figure out the color space. I’m wanting to use linear rendered pipeline and thus all images should be in linear color space and only gamma corrected at the end during tone mapping (HDR) id imagine. HAs anyone used stb_image? is there a way of telling what the input image is encoded as so that I can run my GammaToLinear function on the gamma corrected images?

Thanks,

For all intents and purposes nearly all 8 bit image formats are encoded in sRGB... so you need to run your conversion function, or better tag the format as SRGB when you create the texture and get the conversion on texture samping for 'free' (also note that these days then most filtering (linear, anisotropic) is done in linear color space on the texture filtering hardware, something that you can't easily get if you manually call GammaToLinear, unless you manually do filtering as well... e.g. take multiple samples, convert to linear and then manually filter)

Also note that  most normal maps you should not convert, as mostly they are encoded as if they were linear. Similar for other purpose maps say AO, or specular or roughness.

Also, if you are not 100% sure... a good and simple test is to make a texture that where each line alternates between black and white... then draw a mid gray solid rect next to it... and if you squint the colors should be identical.

Also take special care to note if your display buffer is sRGB or Linear. That seems to trip up a lot of people. But if your display buffer is sRGB (most common case for people starting) then you will need to convert from LinearToGamma just before outputting the pixel/fragment. (Again you can test this by drawing a manual pattern of rects where each line is black/white and then drawing a 0.5 rect next to it and they should be same intensity. By using 0.0 and 1.0 you basically cut out all sRGB -> Linear conversions so you eliminate that area of 'mistake')

Advertisement

Hmm, basically i have a custom image format "name".tex which can be R8G8B8A8_UNORM or DXT1 or DXT5, because im wanting a linear pipline i want to just force all input images from png,jpeg, tiff etc to be Linear space so when i output my .tex its formatted correctly for my Rendering pipline.

But most image loading libaries ive seen dont give you gamma encoded data atleast stb_image doesnt as far as i can tell, so i dont know when to apply my Linear conversion function too the input image.

Quote

because im wanting a linear pipline i want to just force all input images from png,jpeg, tiff etc to be Linear space so when i output my .tex its formatted correctly for my Rendering pipline.

You don't want to be doing that... since that'll introduce banding in the texture for anything stored in 8-bit. If you haven't read: https://en.wikipedia.org/wiki/Gamma_correction you should.

If that still doesn't make sense to you, then just convert a nice gradient texture in your pipeline to linear and store in 8-bit, reload it and you'll see exactly what happens... banding.

Im attemptign to do the following:

Quote

Therefore, typical practice in PBR is to use a linear pipeline. Here, the input colors and textures have their gamma correction removed before shading, putting them into linear space. When shaded, the result is physically correct because the shading process and inputs are all in the same space. After, any post effects should be computed while the frame is still in linear space, as post effects are typically linear, much like shading. Finally the image is then gamma corrected so it will have the proper intensity after the display’s gamma adjustments.

I thought making the image linear on disk would allow me to submit linear to the shader do all the linear calculations then store them on a linear framebuffer that will do the gamma encode ready for the monitor to decode.?

If thats no that case whats the process? I think after research its safe to assume most images will be supplied with gamma encoding (1/2,2) from most art tools. So i just set my surface format too FORMAT_R8G8B8A8_UNORM_SRGB and it will remove the gamma when sampling in the shader?

And yes i understand wha tyou mean about the banding, 8bpp is not enough to encode linear as it makes dark colors unpercise and light colors wastefully percise.

Quote

I thought making the image linear on disk would allow me to submit linear to the shader do all the linear calculations then store them on a linear framebuffer that will do the gamma encode ready for the monitor to decode.?

and

Quote

And yes i understand wha tyou mean about the banding, 8bpp is not enough to encode linear as it makes dark colors unpercise and light colors wastefully percise.

This is the case, but the display itself is not linear... meaning it encoded and hence storing linear values will cull out the values that couldn't be encoded... in the shader when dealing with floats and doing (linear) math operations this is great. but storing those values in 8-bits in linear format means you won't have a lot of values in the 8-bits mapping into the low end of the intensity.

Quote

I think after research its safe to assume most images will be supplied with gamma encoding (1/2,2) from most art tools. So i just set my surface format too FORMAT_R8G8B8A8_UNORM_SRGB and it will remove the gamma when sampling in the shader?

Exactly! This is what most people do.

Just take care not to blindly convert normal maps, spec maps, etc to _SRGB formats, as that'll throw things off.

This topic is closed to new replies.

Advertisement