はじめに
プログラムから, テクスチャ圧縮がしたいです. 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 件のコメント:
コメントを投稿