はじめに
プログラムから, テクスチャ圧縮がしたいです. BC1, BC3, BC6h BC7についてはispc texture compressionを使おうと思っていましたが, BC5がないのです.
ガイドに仕様がちゃんと書いてあります. 簡単そうなので作ってしまいます.
ファイルフォーマット
4x4のブロックごとに圧縮するブロック圧縮です. BC4はRだけの1チャネル, BC5はRGの2チャネルを扱います. 4x4x2 = 32 bytes
を次の tablex2 = 16 bytes
に圧縮します. BC5_UNORMとBC5_SNORMの2バリエーションです. 2つはシェーダでサンプルした場合, [0 1]の浮動小数点数になるか, [-1 1]の浮動小数点になるかが違います.
テーブルは, 4x4の最小値と最大値が先頭に2バイト, 次に3bits x 16のテーブルへのインデックスが並びます.
- /*
- MSB LSB
- | red_0 | 1 byte minimum color
- | red_1 | 1 byte maximum color
- | red_h | red_g | red_f | red_e | red_d | red_c | red_b | red_a | 3 bits x 8
- | red_p | red_o | red_n | red_m | red_l | red_k | red_j | red_i | 3 bits x 8
- */
テーブルは明示的に持たず最大値, 最小値から計算します. UNORMとSNORMで1箇所異なりますが, 圧縮するだけならばどちらでも同じなので統一します.
- static constexpr u32 Shift = 20;
- void createTable(s32 colors[8], s32 block[16])
- {
- colors[0] = block[0];
- colors[1] = block[0];
- for(u32 i = 1; i < 16; ++i) {
- colors[0] = minimum(colors[0], block[i]);
- colors[1] = maximum(colors[1], block[i]);
- }
- colors[0] <<= Shift;
- colors[1] <<= Shift;
- if(colors[1] < colors[0]) {
- // 6 interpolated color values
- colors[2] = (6 * colors[0] + 1 * colors[1]) / 7; // bit code 010
- colors[3] = (5 * colors[0] + 2 * colors[1]) / 7; // bit code 011
- colors[4] = (4 * colors[0] + 3 * colors[1]) / 7; // bit code 100
- colors[5] = (3 * colors[0] + 4 * colors[1]) / 7; // bit code 101
- colors[6] = (2 * colors[0] + 5 * colors[1]) / 7; // bit code 110
- colors[7] = (1 * colors[0] + 6 * colors[1]) / 7; // bit code 111
- } else {
- // 4 interpolated color values
- colors[2] = (4 * colors[0] + 1 * colors[1]) / 5; // bit code 010
- colors[3] = (3 * colors[0] + 2 * colors[1]) / 5; // bit code 011
- colors[4] = (2 * colors[0] + 3 * colors[1]) / 5; // bit code 100
- colors[5] = (1 * colors[0] + 4 * colors[1]) / 5; // bit code 101
- colors[6] = 0; // bit code 110
- colors[7] = 255<<Shift; // bit code 111
- }
- }
ピクセル値に最も近いテーブルインデックスを検索して, 符号化します.
- u64 findNearest(s32 colors[8], s32 x)
- {
- u32 index = 0;
- s32 mind = absolute(colors[0] - x);
- for(u32 i = 1; i < 8; ++i) {
- s32 d = absolute(colors[i] - x);
- if(d < mind) {
- mind = d;
- index = i;
- }
- }
- return index;
- }
まとめ
GPUOpen Compressonatorと結果が異なるため, もっといい方法がありそうです.
0 件のコメント:
コメントを投稿