Skip to content
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

BC4/5 blocks with two values per channel are slightly off #17

Open
cwoffenden opened this issue Sep 4, 2022 · 1 comment · May be fixed by #18
Open

BC4/5 blocks with two values per channel are slightly off #17

cwoffenden opened this issue Sep 4, 2022 · 1 comment · May be fixed by #18

Comments

@cwoffenden
Copy link

cwoffenden commented Sep 4, 2022

If a BC4 block has only two values, and the search radius is greater than zero, then the second value is always interpolated, and since the BC4/5 interpolation is done with more than 8-bits in hardware (see findings here) the resulting value is slightly off.

If you start with the code here:

for (int lo_delta = -(int)search_rad; lo_delta <= (int)search_rad; lo_delta++)

An example being: a block with values 126 and 127 and the default search radius of 3 will achieve a best_err of zero with endpoints 127 and 123 (with six interpolated values, MODE8 in the code). When interpolated as 8-bit, and with selectors of 0 and 2, this does correctly result in values of 126 and 127. But... since the hardware is using 14- or 16-bit interpolation then the resulting values are 126.43 and 127.0.

This is small, agreed, but when mixed with solid blocks of 126 we get block artefacts as the encoder flips between solid and multi-value blocks, breaking down to blocks of 126.0 and 126.43.

This came about because we have a normal map exported from 3D Coat with essentially a dimple noise texture on it. AFAIK it was worked on at 4k then exported at 2k, by which time the dimple texture end up being a few dots. Here's the result isolated with obvious block errors:

rgbcx

Ignoring there's clearly something amiss with the normal map, it does nicely highlight this issue. If this were BC3 alpha it wouldn't be affected, it's only BC4/5 with the extended interpolation bits.

The easy fix (which I've already tried) is to clamp the search radius to zero when there are only two values. I think, though, a better fix may be to interpolate with more range in bc4_block::get_block_values() so that it works for more than two values (which I'll try next).

@cwoffenden
Copy link
Author

For reference, here's the original 3D Coat nmap:

Piano_Gold_nmap

And here's a cropped section I've been stepping through the code with:

problematic-piano-nmap

(Taken from the bottom left, cropped on the same 4x4 boundaries as the encoder)

cwoffenden added a commit to cwoffenden/bc7enc_rdo that referenced this issue Sep 4, 2022
This fixes richgel999#17 but goes further, since it provides higher accuracy for other blocks with few values. Two value blocks are special-cased to use the two endpoints. An early out is taken when the error reaches zero.
@cwoffenden cwoffenden linked a pull request Sep 4, 2022 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant