BC7 格式是紋理壓縮格式,用於 RGB 和 RGBA 資料的高品質壓縮。
如需 BC7 格式區塊模式的詳細資訊,請參閱 BC7 格式模式參考。
關於 BC7/DXGI_FORMAT_BC7
BC7 是由下列DXGI_FORMAT列舉值所指定:
- DXGI_FORMAT_BC7_TYPELESS。
- DXGI_FORMAT_BC7_UNORM。
- DXGI_FORMAT_BC7_UNORM_SRGB。
BC7 格式可用於 Texture2D(包括數位)、Texture3D 或 TextureCube(包括數位)紋理資源。 同樣地,此格式適用於與這些資源相關聯的任何 MIP 對應表面。
BC7 使用固定區塊大小 16 個字節(128 位),而固定磚大小為 4x4 紋素。 如同先前的 BC 格式,大於支援的磚大小 (4x4) 的紋理影像會使用多個區塊來壓縮。 此尋址識別也適用於三維影像和 MIP 地圖、Cubemap 和紋理數位。 所有影像磚的格式都必須相同。
BC7 會壓縮三通道 (RGB) 和四通道 (RGBA) 固定點數據影像。 一般而言,源數據是每個色彩元件 8 位(通道),不過格式能夠編碼每個色彩元件具有較高位的源數據。 所有影像磚的格式都必須相同。
BC7 譯碼器會在套用紋理篩選之前執行解壓縮。
BC7 解壓縮硬體必須精確位;也就是說,硬體必須傳回與本檔所述譯碼器所傳回的結果完全相同的結果。
BC7 實作
BC7 實作可以指定 8 種模式的其中一種,而模式在 16 位元組 (128 位) 區塊中指定最小有效位。 模式會以零或多個位編碼,其值為0,後面接著1。
BC7 區塊可以包含多個端點組。 針對本檔的目的,對應至端點組的索引集合可能稱為「子集」。此外,在某些區塊模式中,端點表示法會以同樣的方式編碼,基於本檔的目的,應該稱為 “RGBP”,其中 “P” 位代表端點色彩元件的共用最小有效位。 例如,如果格式的端點表示法是 “RGB 5.5.5.1”,則端點會解譯為 RGB 6.6.6 值,其中 P 位的狀態會定義每個元件的最小有效位。 同樣地,如果是具有 Alpha 色板的源數據,如果格式的表示法是 “RGBAP 5.5.5.5.1”,則端點會解譯為 RGBA 6.6.6.6。 根據區塊模式,您可以個別指定子集兩個端點的共用最小有效位(每個子集 2 個 P 位),或在子集的端點之間共用 (每個子集 1 個 P 位)。
對於未明確編碼 Alpha 元件的 BC7 區塊,BC7 區塊包含模式位、分割區位、壓縮端點、壓縮索引和選擇性 P 位。 在這些區塊中,端點具有僅限 RGB 表示法,而且源數據中所有紋素的 Alpha 元件都會譯碼為 1.0。
對於結合色彩和 Alpha 元件的 BC7 區塊,區塊包含模式位、壓縮端點、壓縮索引,以及選擇性分割區位和 P 位。 在這些區塊中,端點色彩會以 RGBA 格式表示,而 Alpha 元件值會與色彩元件值一起插補。
針對具有個別色彩和 Alpha 元件的 BC7 區塊,區塊包含模式位、旋轉位、壓縮端點、壓縮索引,以及選擇性的索引選取器位。 這些區塊具有有效的 RGB 向量 [R、G、B] 和純量 Alpha 色板 [A] 分別編碼。
下表列出每個區塊類型的元件。
| BC7 區塊包含... | 模式位 | 旋轉位 | 索引選取器位 | 數據分割位 | 壓縮的端點 | P 位 | 壓縮索引 |
|---|---|---|---|---|---|---|---|
| 僅限色彩元件 | 必填 | N/A | N/A | 必填 | 必填 | 自選 | 必填 |
| color + alpha combined | 必填 | N/A | N/A | 自選 | 必填 | 自選 | 必填 |
| 色彩和 Alpha 分隔 | 必填 | 必填 | 自選 | N/A | 必填 | N/A | 必填 |
BC7 會在兩個端點之間的近似線條上定義色彩調色盤。 模式值會決定每個區塊插補端點組的數目。 BC7 會為每個材質儲存一個調色盤索引。
針對對應至一組端點的每個索引子集,編碼器會修正該子集壓縮索引數據的一位狀態。 它藉由選擇端點順序來允許指定之「修正」索引的索引將其最重要的位設定為0,然後可以捨棄,為每個子集儲存一個位。 對於只有單一子集的區塊模式,修正索引一律為索引 0。
譯碼 BC7 格式
下列虛擬程式代碼概述在16位元組BC7區塊下解壓縮像素位於 (x,y) 的步驟。
decompress_bc7(x, y, block)
{
mode = extract_mode(block);
//decode partition data from explicit partition bits
subset_index = 0;
num_subsets = 1;
if (mode.type == 0 OR == 1 OR == 2 OR == 3 OR == 7)
{
num_subsets = get_num_subsets(mode.type);
partition_set_id = extract_partition_set_id(mode, block);
subset_index = get_partition_index(num_subsets, partition_set_id, x, y);
}
//extract raw, compressed endpoint bits
UINT8 endpoint_array[2 * num_subsets][4] = extract_endpoints(mode, block);
//decode endpoint color and alpha for each subset
fully_decode_endpoints(endpoint_array, mode, block);
//endpoints are now complete.
UINT8 endpoint_start[4] = endpoint_array[2 * subset_index];
UINT8 endpoint_end[4] = endpoint_array[2 * subset_index + 1];
//Determine the palette index for this pixel
alpha_index = get_alpha_index(block, mode, x, y);
alpha_bitcount = get_alpha_bitcount(block, mode);
color_index = get_color_index(block, mode, x, y);
color_bitcount = get_color_bitcount(block, mode);
//determine output
UINT8 output[4];
output.rgb = interpolate(endpoint_start.rgb, endpoint_end.rgb, color_index, color_bitcount);
output.a = interpolate(endpoint_start.a, endpoint_end.a, alpha_index, alpha_bitcount);
if (mode.type == 4 OR == 5)
{
//Decode the 2 color rotation bits as follows:
// 00 – Block format is Scalar(A) Vector(RGB) - no swapping
// 01 – Block format is Scalar(R) Vector(AGB) - swap A and R
// 10 – Block format is Scalar(G) Vector(RAB) - swap A and G
// 11 - Block format is Scalar(B) Vector(RGA) - swap A and B
rotation = extract_rot_bits(mode, block);
output = swap_channels(output, rotation);
}
}
下列虛擬程式代碼概述為每個子集完整譯碼端點色彩和 Alpha 元件的步驟,該子集指定了 16 位元組 BC7 區塊。
fully_decode_endpoints(endpoint_array, mode, block)
{
//first handle modes that have P-bits
if (mode.type == 0 OR == 1 OR == 3 OR == 6 OR == 7)
{
for each endpoint i
{
//component-wise left-shift
endpoint_array[i].rgba = endpoint_array[i].rgba << 1;
}
//if P-bit is shared
if (mode.type == 1)
{
pbit_zero = extract_pbit_zero(mode, block);
pbit_one = extract_pbit_one(mode, block);
//rgb component-wise insert pbits
endpoint_array[0].rgb |= pbit_zero;
endpoint_array[1].rgb |= pbit_zero;
endpoint_array[2].rgb |= pbit_one;
endpoint_array[3].rgb |= pbit_one;
}
else //unique P-bit per endpoint
{
pbit_array = extract_pbit_array(mode, block);
for each endpoint i
{
endpoint_array[i].rgba |= pbit_array[i];
}
}
}
for each endpoint i
{
// Color_component_precision & alpha_component_precision includes pbit
// left shift endpoint components so that their MSB lies in bit 7
endpoint_array[i].rgb = endpoint_array[i].rgb << (8 - color_component_precision(mode));
endpoint_array[i].a = endpoint_array[i].a << (8 - alpha_component_precision(mode));
// Replicate each component's MSB into the LSBs revealed by the left-shift operation above
endpoint_array[i].rgb = endpoint_array[i].rgb | (endpoint_array[i].rgb >> color_component_precision(mode));
endpoint_array[i].a = endpoint_array[i].a | (endpoint_array[i].a >> alpha_component_precision(mode));
}
//If this mode does not explicitly define the alpha component
//set alpha equal to 1.0
if (mode.type == 0 OR == 1 OR == 2 OR == 3)
{
for each endpoint i
{
endpoint_array[i].a = 255; //i.e. alpha = 1.0f
}
}
}
若要為每個子集產生每個插補元件,請使用下列演算法:讓 「c」 成為要產生的元件;讓 「e0」 成為子集端點 0 的元件;讓 「e1」 成為子集端點 1 的元件。
UINT16 aWeights2[] = {0, 21, 43, 64};
UINT16 aWeights3[] = {0, 9, 18, 27, 37, 46, 55, 64};
UINT16 aWeights4[] = {0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64};
UINT8 interpolate(UINT8 e0, UINT8 e1, UINT8 index, UINT8 indexprecision)
{
if(indexprecision == 2)
return (UINT8) (((64 - aWeights2[index])*UINT16(e0) + aWeights2[index]*UINT16(e1) + 32) >> 6);
else if(indexprecision == 3)
return (UINT8) (((64 - aWeights3[index])*UINT16(e0) + aWeights3[index]*UINT16(e1) + 32) >> 6);
else // indexprecision == 4
return (UINT8) (((64 - aWeights4[index])*UINT16(e0) + aWeights4[index]*UINT16(e1) + 32) >> 6);
}
下列虛擬程式代碼說明如何擷取色彩和Alpha元件的索引和位計數。 具有個別色彩和 Alpha 的區塊也有兩組索引數據:一組用於向量通道,另一組用於純量通道。 對於模式 4,這些索引的寬度不同(2 或 3 位),而且有一個位選取器,指定向量或純量數據是否使用 3 位索引。 (擷取 Alpha 位計數類似於擷取色彩位計數,但以 idxMode 位為基礎的反向行為。
bitcount get_color_bitcount(block, mode)
{
if (mode.type == 0 OR == 1)
return 3;
if (mode.type == 2 OR == 3 OR == 5 OR == 7)
return 2;
if (mode.type == 6)
return 4;
//The only remaining case is Mode 4 with 1-bit index selector
idxMode = extract_idxMode(block);
if (idxMode == 0)
return 2;
else
return 3;
}
相關主題
-
Direct3D 11 中的 紋理區塊壓縮