3D 模型為什麼這麼大?
你的模型在偷偷變胖
你匯出了一個 GLB 檔案,10MB,感覺還行。傳到手機上一打開——白屏、卡頓,甚至直接崩潰。
在電腦上沒問題,到了手機上就爆炸。這不是程式的鍋,而是 3D 模型有一個不太直覺的特性:它在磁碟上和顯存裡,完全不是一個大小。
一張 JPG 圖片在磁碟上可能只有 200KB。但 GPU 不認識 JPG,它只認識原始像素。所以上傳到顯存之前,這張圖會被完全解壓縮。一張 2048x2048 的貼圖,解壓縮後要吃掉約 22MB 顯存。如果你用了 6 張貼圖(albedo、normal、roughness、metallic、AO、emissive),光一個材質就要 132MB。
手機總共可能也就 2-4GB 顯存,一個模型的貼圖就吃了 3-6%。場景裡有 10 個模型呢?
拆開看看,體積都花在哪了
一個典型的 GLB 模型主要由三部分組成:頂點資料、貼圖,以及元資料和動畫。
拿一個真實的 PBR 模型來看:
| 組成部分 | 具體內容 | 典型佔比 | 說明 |
|---|---|---|---|
| 貼圖 | albedo、normal、roughness、metallic、AO 等 | 70-85% | 幾乎永遠是體積大戶 |
| 頂點資料 | position、normal、UV、tangent、顏色 | 10-20% | 取決於模型複雜度 |
| 動畫資料 | 骨骼、蒙皮、關鍵幀 | 0-15% | 有動畫才有 |
| 其他 | 材質定義、場景結構、相機 | < 2% | 可忽略 |
貼圖佔了 80% 左右。很多時候你以為要最佳化的是頂點,但真正佔地方的是貼圖。
「磁碟小」不等於「顯存小」
這可能是理解 3D 效能最關鍵的一個點。
PNG 和 JPG 是為網路傳輸設計的——磁碟上很小,下載快。但 GPU 不能直接使用它們,必須先完全解壓縮成原始像素。計算方法:
顯存佔用 = 寬度 * 高度 * 4位元組(RGBA) * 1.333(含mipmap)
一張 4096x4096 的 RGBA 貼圖:
| 指標 | 數值 |
|---|---|
| PNG 檔案大小 | ~8MB |
| JPG 檔案大小 | ~1.5MB |
| 顯存佔用(含 mipmap) | ~87MB |
1.5MB 的 JPG,到了顯存裡變成 87MB。
Mipmap 是什麼? GPU 會為貼圖產生一系列逐級縮小的版本,從原始大小到 1x1 像素,每個級別是上一級的一半。這讓遠處的物體渲染更快更清晰,但要多佔約 33% 的顯存。幾乎所有的 3D 應用都會用 mipmap,所以這個開銷基本是標配。
所以 PNG/JPG 就像旅行壓縮袋——壓縮之後小小的方便帶,到了目的地得全部撐開。下載快了,但顯存一點沒省。
顯存不夠會怎樣
不會彈個「顯存不足」的提示框。實際情況更糟糕:
- 行動端:頁面白屏,或者系統直接殺掉分頁
- VR 頭顯:掉幀。VR 裡掉幀不是「有點卡」,是會引起暈眩的
- 桌面端:貼圖閃爍、降級、渲染變慢
Reddit 上有個開發者做 WebXR 藝廊,往 Quest 上塞了 60 張立體圖。一開始正常,後來越來越不穩定直到崩潰。他花了幾天查程式碼,最後發現從來沒認真想過 VRAM 這回事——就是一直在往 GPU 裡塞 JPG。
壓縮的兩條路
3D 模型壓縮主要分兩個方向:
頂點壓縮——把頂點座標、法線、UV 等幾何資料用更緊湊的方式儲存。例如把 32 位元浮點數換成 16 位元整數(這叫 quantization,量化)。代表性方案:Draco、MeshOpt、KHR_mesh_quantization。
貼圖壓縮——讓貼圖在顯存裡也保持壓縮狀態。GPU 在取樣時即時解碼單個像素,幾乎沒有效能開銷。代表性方案:KTX2 + Basis Universal。
| 頂點壓縮 | 貼圖壓縮 | |
|---|---|---|
| 減什麼 | 幾何資料 | 貼圖 |
| 典型效果 | 縮小 50-90% | 磁碟減 50-70%,顯存減 75% |
| 有損嗎 | 是,精度下降 | 是,畫質下降 |
| 適用場景 | 頂點密集的模型 | 幾乎所有 PBR 模型 |
| 詳見 | 第 2 篇 | 第 3、4 篇 |
一個常見誤區:用了 Draco 壓縮頂點就覺得萬事大吉。但貼圖佔了模型 80% 的體積,你把頂點砍一半,整體可能只瘦了 10%。兩頭都得管。
沒有一種方法通吃所有場景
這是整個系列的核心觀點:
不同平台、不同裝置、不同使用方式,需要不同的壓縮策略。
| 場景 | 首要瓶頸 | 重點關注 |
|---|---|---|
| 桌面 Web 展示 | 下載速度 | 檔案大小 |
| 行動瀏覽器 | 顯存 | 貼圖壓縮 |
| VR 頭顯 | 顯存 + 幀率 | 貼圖壓縮 + 頂點簡化 |
| 微信小程式 | 包大小 + 相容性 | 輕量方案(MeshOpt) |
| 大型場景 | 顯存 + draw call | 全方位壓縮 + LOD |
後面的每一篇不會只說「用 X 就對了」,而是會講清楚:X 適合什麼場景,什麼時候反而幫倒忙,什麼情況下該用 Y。
下一步
這篇搞清楚了問題。下一篇動手——認識頂點壓縮三把工具:量化、MeshOpt 和 Draco。