BinomialLLC / basis_universal

Basis Universal GPU Texture Codec
Apache License 2.0
2.7k stars 263 forks source link

Colors become lighter when transcoding .basis to .ktx #347

Open omri-polycam opened 1 year ago

omri-polycam commented 1 year ago

Hello, I'm trying to use basisu to bundle and compress the 6 images of a cube map. It does work, however the resulting .ktx file ends up considerably lighter than the source file. I am using filament as my rendering engine which unfortunately does not support ktx2 cubemaps (I'm stuck on just .ktx) and the compressed format must work on mac, webassembly, iOS and Android so my supported compression formats are limited.

Here is how I compress to .basis and then to .ktx

basisu -tex_type cubemap Face_2.jpg Face_0.jpg Face_4.jpg Face_5.jpg Face_1.jpg Face_3.jpg
basisu -unpack -ktx_only -format_only 1 Face_2.basis

It appears to me the problem is in the .basis to .ktx step. I say this because unpacking the .basis file to .png produces the correct colors. I use the following command to unpack to .pngs: basisu -unpack -no_ktx Face_2.basis

Let me know if you have any suggestions as to what might be wrong. None of the sRGB/linear basisu command line options seem to help. According to filament the final .ktx file is in linear and not sRGB color space. See the below screen shots.

One of the 6 source images: Face_2

One of the 6 images unpacked from the .basis file to .png with correct colors: Face_2_unpacked_rgba_PVRTC2_4_RGBA_0000

A screenshot from the mac preview application of the .ktx file with the overly light colors. Filament displays the same overly light colors. Screenshot

Thanks, Omri

richgel999 commented 1 year ago

Thanks, this appears to be a sRGB vs. linear issue. I will grab a mac and see if I can reproduce.

omri-polycam commented 1 year ago

Hi, so I found one hacky solution where the colors now look right that might help shed some light on the problem. If I preprocess the colors of every color component of every pixel using the sRGB to linear equation prior to calling basisu, it seems to work. Below is my code to do so:

static constexpr auto color_threshold = 0.04045f;
static constexpr auto low_color_denominator = 12.92f;
static constexpr auto color_addition = 0.055f;
static constexpr auto color_denominator = 1.055f;
static constexpr auto color_exponent = 2.4f;

static float SrgbToLinear(float color) {
  if (color <= color_threshold) {
    return (color / low_color_denominator);
  } else {
    return (std::pow((color + color_addition) / color_denominator, color_exponent));
  }
}

I attached one of the faces of the skybox that I am now passing into basisu. Note that it is excessively dark to counteract the excessive lightness I get upon converting to .ktx.

Thanks, Omri

Face_2

richgel999 commented 1 year ago

If I preprocess the colors of every color component of every pixel using the sRGB to linear equation prior to calling basisu, it seems to work.

This implies that somebody is doing a linear->sRGB conversion (not basisu!). You're going to lose quality doing this. I think I know what the problem is: our KTX files are using formats that causing mac to do a linear->sRGB conversion during viewing. The problem is (from memory), if I use the right formats, the other viewer tools that we use to validate our KTX files break. I'm damned if I do, damned if I don't.