-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BC1 colors are not rounded correctly #15
Comments
Hi! Thanks for submitting the issue. |
@RunDevelopment so I tested your "magic" values and they match the floating-point interpolation perfectly! |
Thank you! Yes, those credentials are correct. Just put me wherever you see fit :)
Nice 🎉 |
3b71535 is in, thanks for your help! |
Hi! While analyzing the Rust source port (
bcdec_rs
) of this library, I discovered that BC1 and BC4 are not rounded correctly compared to doing all calculations in float32 and converting the image to 8 bit ints at the very end. I then confirmed that the Rust source port simply faithfully recreated the issues from the original bcdec C library. While there's already an issue for BC4 (#12), there wasn't one for BC1 yet. (Here's the issue I made for the Rust source port for reference: ScanMountGoat/image_dds#17)What's the issue?
Colors are not rounded correctly. I define "correct" here are doing all calculations in float32 and then converting the decoded float32 image to uint8 at the very end. I'm using this definition, because that's how DirectXTex is implemented, and it's how Paint.net and GIMP decode DDS images. So this definition of correct is widely-used in modern software.
How is it incorrect: the R, G, and B color channels can be off by to +-1. The error is only a single bit. While small, it's still noticeable. The problem is that the error is not the same between channels. So e.g. the R and B channels can have an error of -1 while the G channel can have an error of +1, which will cause a noticeable green tint.
Here's an example image showing this exact problem. All pixels in this image are supposed to have the color RGB=47 47 47, as is the case when opened in Paint.net and Gimp, but bcdec will decode all pixels as RGB=46 48 46.
BC1_UNORM_SRGB-47.zip
These rounding errors are also not rare. Here's a test image and all error magnified so we can see them:
The cause of the issue
The cause is that the issue is that bcdec uses the already-rounded 8-bit values for
color0
andcolor1
to calculate the values forcolor2
andcolor3
.E.g. if the 5-bit value of
r
is 29, then the 8-bit value is 238.55 which is rounded to 239. That's not a problem forcolor0
andcolor1
, because that's just want correct rounding does, but it is a problem forcolor2
andcolor3
. This rounding forcolor0/1
created an error of 0.45 which is then multiplied by 2 when calculatingcolor2/3
giving us an error of 0.9. This error is capable of changing the rounding ofcolor2
andcolor3
.The fix
The fix is to use the original 5/6-bit values for interpolation instead of the rounded 8-bit values. E.g. if
r0_5
andr1_5
are the 5-bit values ofcolor0
andcolor1
respectively, then the RGB values ofcolor_2 = 2/3*color_0 + 1/3*color_1
can be calculated as(Note that
g
must be calculated with 32-bit integers, while 16-bit integers are enough forr
andb
).I got these constants using a script I made that uses a brute-forces search. This script also found the same constants bcdec uses for the 5/6 bit to 8 bit conversion used for
color0
andcolor1
.Note that BC1A mode requires different constants. Here
color_2 = 1/2*color_0 + 1/2*color_1
can be calculated as(Just as before, 32 bit for
g
and 16 bit forr
andb
.)The text was updated successfully, but these errors were encountered: