1. 程式人生 > >S3TC(S3 Texture Compression)紋理壓縮格式詳解

S3TC(S3 Texture Compression)紋理壓縮格式詳解

使用S3TC格式儲存的壓縮紋理是以4X4的紋理單元塊(texel blocks)為基本單位儲存的,每紋理單元塊(texel blocks)有64bit或者128bit的紋理單元資料(texel data)。這樣就要求每張貼圖長度和寬度應該是4的倍數。影象如同一般的做法按照行列順序存放這些4X4的紋理單元塊(texel blocks),每個texel blocks被看成是一個影象的“畫素”。對於那些長度不為4的倍數的貼圖,多出來的那些紋理單元在壓縮的時候要麼捨棄不被放到影象中或者不足4的會被補上空位按4處理。

對於一個長度為w,寬為h,並且塊大小為blocksize的影象,它的大小為(用位元組計算)
ceil(w/4) * ceil(h/4) * blocksize

在解碼一個S3TC影象的時候,可以通過下面的式子得到一個紋理單元(x,y)所位於的塊的地址(用位元組計算)
blocksize * (ceil(w/4) * floor(y/3) + floor(x/4))

通過紋理單元(x,y)獲得它所處於的塊的下標:
(x % 4 , y % 4)

有4種不同的S3TC影象格式:
1.COMPRESSED_RGB_S3TC_DXT1_EXT

每個4X4的紋理單元塊包含8個位元組的RGB資料,也就是說每個影象塊被編碼為順序的8個位元組(64bit),按照地址的順序,它們分別是:
c0_lo,c0_hi,
c1_lo,c1_hi,
bits_0,bits_1,bits_2,bits_3

塊的8個位元組被用來表達3個量:
color0 = c0_lo + c0_hi * 256
color1 = c1_lo + c1_hi * 256
bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * bits_3))
color0和color1是16位的無符號整數,用來表達顏色,格式是RGB - UNSIGNED_SHORT_5_6_5。分別用RGB0和RGB1來表示
bits是一個32位的無符號整數,從bits可以求出位於(x,y)的紋理單元的2位控制碼:(x,y介於0-3之間)
code(x,y) = bits[2 * (4 * y + x) + 1..2 * (4 * y + x) + 0] 即,2 * (4 * y + x) + 1位和2 * (4 * y + x)位
bits的第31位是高位,第0位是低位

這樣可以求出位於(x,y)的紋理單元的RGB值:
RGB0, if color0 > color1 and code(x,y) == 0
RGB1, if color0 > color1 and code(x,y) == 1
(2*RGB0+RGB1)/3, if color0 > color1 and code(x,y) == 2
(RGB0+2*RGB1)/3, if color0 > color1 and code(x,y) == 3

RGB0, if color0 <= color1 and code(x,y) == 0
RGB1, if color0 <= color1 and code(x,y) == 1
(RGB0+RGB1)/2, if color0 <= color1 and code(x,y) == 2
BLACK, if color0 <= color1 and code(x,y) == 3
這些算術運算都是向量運算,分別對各個分量R,G,B進行計算。BLACK=RGB(0,0,0)

這種格式的S3TC影象不含有Alpha,所以整個影象都是不透明的
2.COMPRESSED_RGBA_S3TC_DXT1_EXT

每個4*4塊包含8位元組的RGB顏色和最小限度的Alpha透明度資料,顏色資料的提取方式和COMPRESSED_RGB_S3TC_DXT1_EXT是完全一樣的,區別在於Alpha資料:
對於(x,y)處紋理單元的Alpha值,計算方式如下:
0.0, if color0 <= color1 and code(x,y) == 3
1.0, otherwise

注意:
首先,把一個RGBA影象壓縮成為只含有1位Alpha的壓縮格式,所有Alpha<0.5的畫素的Alpha值被置為0.0,而Alpha>=0.5的畫素的Alpha值被置為1.0. 而把一個RGBA影象壓縮成為COMPRESSED_RGBA_S3TC_DXT1_EXT格式的時候。
其次,如果某個紋理單元最終的Alpha為0.0,那麼此紋理單元的R,G,B顏色值都將被置為0.
最後,對於是用此格式的應用,必須遵守這個規則。另外,當一個通用的內部格式被指定後,也許可以使用COMPRESSED_RGB_S3TC_DXT1_EXT格式,但不允許使用COMPRESSED_RGBA_S3TC_DXT1_EXT(應該跟OpenGL有關係)
3.COMPRESSED_RGBA_S3TC_DXT3_EXT

每個4*4塊中包含64bit的未壓縮Alpha資料和64bit的RGB顏色資料,其中顏色資料按照和COMPRESSED_RGB_S3TC_DXT1_EXT一樣的方式編碼,唯一的區別在於2位控制碼被以不明顯的方式編碼,換句話說,就像知道Color0 > Color1,而不需要知道Color0和Color1的具體值。

每個塊的紋理單元的Alpha值被順次編碼為8個位元組:
a0, a1, a2, a3, a4, a5, a6, a7

通過這8個位元組可以得到一個64位的無符號整數:
alpha = a0 + 256 * (a1 + 256 * (a2 + 256 * (a3 + 256 * (a4 + 256 * (a5 + 256 * (a6 + 256 * a7))))))
高位是63位,低位是0位

通過這個alpha就可以獲得位於(x,y)處紋理單元的Alpha值
alpha(x,y) = bits[4*(4*y+x)+3..4*(4*y+x)+0]

4位數字所能表示的最大值是15,所以折算到[0.0,1.0],Alpha = alpha(x,y) / 15
4.COMPRESSED_RGBA_S3TC_DXT5_EXT

每個4*4塊中包含64bit的壓縮過的Alpha資料和64bit的RGB顏色資料,顏色資料部分壓縮方式和COMPRESSED_RGBA_S3TC_DXT3_EXT完全一致。

Alpha資料是8個位元組的壓縮資料,這8個位元組:
alpha0, alpha1, bits_0, bits_1, bits_2, bits_3, bits_4, bits_5

其中alpha0和alpha1為unsigned char型別資料,轉化為實際的Alpha值需要乘上 1 / 255.0

其他的6個數字bits_N,則可以被解碼成為一個48位的無符號整數
bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 + 256 * (bits_4 + 256 * bits_5))))

通過bits(高位47低位0),可以求得位於(x,y)紋理單元的3位控制碼:
code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
根據bits、code(x,y)、alpha0以及alpha1就可以求得(x,y)處紋理單元的Alpha值:
alpha0, code(x,y) == 0
alpha1, code(x,y) == 1
(6*alpha0 + 1*alpha1)/7, alpha0 > alpha1 and code(x,y) == 2
(5*alpha0 + 2*alpha1)/7, alpha0 > alpha1 and code(x,y) == 3
(4*alpha0 + 3*alpha1)/7, alpha0 > alpha1 and code(x,y) == 4
(3*alpha0 + 4*alpha1)/7, alpha0 > alpha1 and code(x,y) == 5
(2*alpha0 + 5*alpha1)/7, alpha0 > alpha1 and code(x,y) == 6
(1*alpha0 + 6*alpha1)/7, alpha0 > alpha1 and code(x,y) == 7
(4*alpha0 + 1*alpha1)/5, alpha0 <= alpha1 and code(x,y) == 2
(3*alpha0 + 2*alpha1)/5, alpha0 <= alpha1 and code(x,y) == 3
(2*alpha0 + 3*alpha1)/5, alpha0 <= alpha1 and code(x,y) == 4
(1*alpha0 + 4*alpha1)/5, alpha0 <= alpha1 and code(x,y) == 5
0.0, alpha0 <= alpha1 and code(x,y) == 6
1.0, alpha0 <= alpha1 and code(x,y) == 7
技術規範連結