WebGL紋理詳解——壓縮紋理的使用


為什么要用壓縮紋理

下面這張圖是一輛陸虎越野車模型所用的紋理,原始分辨率為1024 x 1024。

瀏覽器從服務端加載這樣一張圖片時,其格式通常為JPEG,文件尺寸只有166KB,但是當WebGL處理一張紋理時就需要按照位圖處理(這里所說的位圖是指沒有使用任何壓縮算法的原始圖片數據),如果圖像中每個像素需要RGB三個通道,每個通道需要8位空間,那么整張圖片就需要使用1024 x 1024 x 8 x 3 位的信息,也就是3M,這3M的信息都需要加載到GPU緩存當中,這和圖片文件采用什么樣的壓縮格式沒有任何關系。當調用gl.texImage2D方法時,瀏覽器內部就會將圖片文件進行解壓,轉換成位圖格式。如果圖片包含透明信息,那么RGBA格式那么還要額外增加內存使用。

在簡單了解WebGL處理紋理的過程后,會知道使用JPEG或者PNG文件作為紋理時會有這樣的問題:

  1. 需要有圖片解壓過程,比較耗時。
  2. 因為紋理數據較大,所以傳輸紋理數據耗時較多。
  3. 紋理數據占用內存較多。通常是瀏覽器和GPU各自保存一份位圖數據。

壓縮紋理的出現就是來解決這些問題,經過某種算法壓縮之后的紋理可直接被GPU使用,只有當shader進行紋理查詢(texture lookup)才會進行解壓操作,找到對應位置的像素顏色。GPU通常會對解壓過程進行優化從而提升性能。

瀏覽器的圖片緩存策略

為了更好的了解WebGL處理紋理時如何分配和使用內存,請看下面的實驗。

首先,頁面加載前文提到的陸虎車的紋理,打開Chrome的任務管理器(Task Manager),把 Image Cache 和 GPU Memory 這兩項勾選,查看圖片緩存和GPU內存用量。你可以打開這個demo自行觀察。

這時 Image Cache 顯示:4262K,GPU Memory 顯示:17.7M。

現在,我們注釋掉加載紋理的語句,這時候圖片不會加載,紋理也不會被繪制出來。

此時 Image Cache 顯示:0K,GPU Memory 顯示:13.7M。

如果加載圖片,但是不創建紋理會如何?

結果是 Image Cache顯示:166K,GPU Memory顯示:13.7M。

通過以上觀察可以推出以下結論。

  • 當僅下載圖片時 Image Cache 以圖片原始格式進行緩存,當創建紋理時,瀏覽器會解壓成為位圖格式,並將位圖數據進行緩存。
  • GPU Memory 以位圖格式保存紋理數據。
  • 通過Chrome的Profile工具可以看到在JavaScript層面,其內存消耗只包含HTMLImageElement對象所占用的內存大小。

以上結論可以用下面這張圖來概括:

當使用壓縮紋理時,內存使用狀況變為:

壓縮紋理的種類

不同的GPU廠商會有不同的紋理壓縮格式,具體如下:

  • S3TC/DXTn/BCn:桌面計算機常見的壓縮格式。名字雖然有不同叫法,但都是指同一種壓縮方式。通常以DDS文件格式保存。
  • PVRTC/PVRTC2:iOS設備上使用的壓縮紋式。
  • ETC/ETC2:隨着OpenGL ES 2.0 出現。
  • ASTC:2012年出現的一種新壓縮格式。
  • ATC:Adreno GPU支持的一種壓縮格式,Android手機上常用。

壓縮紋理支持情況

WebGL1.0里,壓縮紋理是通過擴展支持的,因此要看當前瀏覽器支持哪些擴展。具體判斷方法如下:

var availableExtensions = gl.getSupportedExtensions();
for (var i = 0; i < availableExtensions.length; i++) {
    if (availableExtensions[i].indexOf('texture') >= 0
        && availableExtensions[i].indexOf('compressed') >= 0) {
        // show in console
        console.log(availableExtensions[i]);
    }
}

 

在我的Macbook Pro Chrome上,上面代碼片段會輸出如下結果:

WEBGL_compressed_texture_s3tc

也就是說,Macbook Pro Chrome支持S3TC格式的壓縮紋理。

下面表格列舉了一些設備和瀏覽器對壓縮紋理的支持情況:

壓縮紋理工具

下面的工具可以將JPEG、PNG等常見的圖片轉換為壓縮紋理。此外還有很多在線轉換工具,這里就不一一列出了。

壓縮紋理實戰

下面我們來通過實例來看如何實現壓縮紋理。由於兼容性,我們首先准備不同格式的壓縮紋理(可以用上面提到的工具提前對紋理進行壓縮)。

完整代碼請見這里

下面來分析一下核心代碼,初始化時首先判斷當前瀏覽器支持什么格式的壓縮紋理,判斷方法如下:

var compressedTextureType = ['s3tc', 'etc1', 'pvrtc'];
var currentCompressedTextureType = null;
 
function getSupportedCompressedTextureType() {
    var availableExtensions = gl.getSupportedExtensions();
    for (var i = 0; i < availableExtensions.length; i++) {
        for (var j = 0; j < compressedTextureType.length; j++) {
            if (availableExtensions[i].indexOf(compressedTextureType[j]) > 0) {
                var extension = gl.getExtension(availableExtensions[i]);
                // 下面這句話必須在getExtension之后調用
                var formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
                console.log(formats);
                for (var key in extension) {
                    console.log(key, extension[key], '0x' + extension[key].toString(16));
                }
                return {
                    type: compressedTextureType[j],
                    extension: extension,
                    formats: formats
                };
            }
        }
    }
}

 

我的Chrome瀏覽器運行后會打印如下信息:

formats是一個數組,可以看到里面有四個數值:[33776, 33777, 33778, 33779]

遍歷extension會打印如下信息:
COMPRESSED_RGB_S3TC_DXT1_EXT 33776 0x83f0
COMPRESSED_RGBA_S3TC_DXT1_EXT 33777 0x83f1
COMPRESSED_RGBA_S3TC_DXT3_EXT 33778 0x83f2
COMPRESSED_RGBA_S3TC_DXT5_EXT 33779 0x83f3

這些信息就是瀏覽器支持壓縮紋理的具體格式,可以看到formats和extension中的信息是一樣的。只不過一個是數組,一個是對象。可以根據這些信息提前准備好壓縮格式。

在創建紋理的代碼中,使用 gl.compressedTexImage2D 替換原有的 gl.texImage2D 方法:

1
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, type, width, height, 0, source);

這里 type 是前面通過extension獲取到的那些常量,需要根據當前紋理的具體格式選擇。source就是壓縮紋理的數據,這里需要注意的是不同壓縮格式獲取數據的方法都不一樣,通常壓縮紋理開頭部分存放一些描述信息,之后才是真正的紋理數據。

在Chrome中使用壓縮紋理后,打開Task Manager后可以看到 Image Cache 變為 0K,GPU Memory 也比之前有所下降。

壓縮紋理的優勢是節省內存開銷,但是紋理文件的尺寸卻比原來的JPG或者PNG要大,因此會影響加載的時間。那么項目當中是否要用壓縮紋理就需要權衡了。如果你的3D場景同時使用的紋理較多或者其他因素導致內存消耗較大,同時需要長時間運行,那么你可以考慮使用壓縮紋理,在場景初始化時需要預先加載必要的紋理,同時通過進度條指示狀態,這種做法類似大型3D游戲的初始化。要注意控制紋理的分辨率,過大的紋理壓縮之后仍然會上兆,這非常影響加載速度。

 

轉載自:http://www.jiazhengblog.com/blog/2017/02/16/3076/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM