入門ガイド

テクスチャは GPU の中でどうなるのか

300 KB の PNG が、知らないうちに 5 MB のグラフィックスメモリを占めることがあります。このガイドでは、その理由、GPU がブロック圧縮でテクスチャを小さくする仕組み、そしてフォーマットの選び方を説明します。どの考え方にも実際に試せるデモがあります。

約 10 分インタラクティブデモ 5 個
読み始める

第 1 章

ファイルサイズはメモリサイズではない

PNG や JPEG は画像を保存・送信するための形式です。GPU がテクスチャを描画する前に、画像は生のテクセルに展開されます。通常は 1 テクセルあたり 4 バイトです。

GPU はフレームごとにテクセルを何百万回もサンプリングするため、いつでも読める状態にしておく必要があります。そのためメモリ使用量は解像度とピクセル形式だけで決まり、ファイルの圧縮率とは関係ありません。遠くの面に使う縮小コピーであるミップマップを加えると、さらに約 3 分の 1 増えます。

試してみるグラフィックスメモリ計算機解像度とテクスチャ数を変えて、同じテクスチャが各フォーマットでどれだけ GPU メモリを使うかを確認できます。
解像度
  • RGBA8
    1 テクセルあたり 32 ビット
    213 MiB
    基準
    1 枚あたり 21.3 MiB
  • BC7 · ASTC 4×4
    1 テクセルあたり 8 ビット
    53.3 MiB
    4 分の 1
    1 枚あたり 5.3 MiB
  • BC1 · ETC2 RGB
    1 テクセルあたり 4 ビット
    26.7 MiB
    8 分の 1
    1 枚あたり 2.7 MiB
  • ASTC 6×6
    1 テクセルあたり 3.56 ビット
    23.8 MiB
    9 分の 1
    1 枚あたり 2.4 MiB
  • ASTC 8×8
    1 テクセルあたり 2 ビット
    13.3 MiB
    16 分の 1
    1 枚あたり 1.3 MiB
  • ASTC 12×12
    1 テクセルあたり 0.89 ビット
    6 MiB
    35.7 分の 1
    1 枚あたり 612 KiB

ブロックフォーマットは各ミップレベルで完全なブロック単位に切り上げているため、GPU が実際に確保する量と一致します。

第 2 章

GPU が PNG をそのまま使えない理由

シェーダーがテクスチャをサンプリングするとき、どのテクセルをどの順番で要求するかはわかりません。ハードウェアはそのテクセルをすぐに見つける必要があります。

PNG や JPEG は可変長の符号化を使うため、途中のピクセルを読むにはその前をすべてデコードしなければなりません。GPU フォーマットは固定レートで、どの 4×4 ブロックもまったく同じバイト数を使います。そのため任意のテクセルのアドレスは掛け算一つで求まります。テクスチャはメモリ内で圧縮されたまま保持され、テクスチャユニットが読み込み時にブロックをデコードします。

試してみるテクセルを探すこの 32×32 テクスチャのテクセルをクリックしてください。ブロックフォーマットなら保存場所を計算できますが、PNG ではできません。

矢印キーで選択位置を移動できます。

選択中のテクセル
x 13、y 18
所属するブロック
3 列、4 行
BC1 でのアドレス
(4 × 8 + 3) × 8 バイト = 280 バイト目

メモリ上に並んだ 64 個のブロック

0511

同じテクセルを PNG で読む場合

先に 0 行目から 18 行目まで展開が必要(32 行中 19 行)

第 3 章

4×4 ブロックの中身

最も古くから広く使われている BC1 は、考え方を一番わかりやすく示してくれます。16 テクセルのブロックをわずか 8 バイトに収めます。

エンコーダーは 2 つの端点カラーを選びます。デコーダーはそれらを混ぜて直線上の 4 色を作り、各テクセルは最も近い色を指す 2 ビットの番号だけを持ちます。色がなめらかに変化するブロックはきれいに残りますが、無関係な色が混在するブロックは崩れます。

試してみるBC1 ブロックエクスプローラーサンプルテクスチャから 4×4 ブロックを選び、BC1 がそれをどう保存するのかを見てみましょう。
ブロック 12, 4

第 4 章

フォーマットごとに異なるトレードオフ

新しいフォーマットは BC1 より賢くビットを使います。端点を増やしたり、ブロック内に複数のカラーラインを持たせたり、アルファを改善したり、ブロックサイズを選べるようにしたりしています。

BC7 と ASTC 4×4 は 1 テクセルあたり 8 ビットで、原画にかなり近い見た目になります。ASTC はブロックサイズで品質とサイズを調整できます。ブロックは常に 128 ビットなので、12×12 ブロックでは 1 テクセルあたり 1 ビット未満になります。Basis Universal は別の方法を取ります。コンパクトなファイルを 1 つだけ配布し、端末上でその GPU が対応するフォーマットにトランスコードします。

主な GPU テクスチャフォーマット
フォーマットテクセルあたりのビット数アルファ主なプラットフォーム向いている用途
BC141 ビットデスクトップ、ゲーム機メモリに余裕がないときの不透明なカラー
BC38ありデスクトップ、ゲーム機古いコンテンツでのなめらかなアルファ付きカラー
BC44データチャンネルデスクトップ、ゲーム機単一チャンネル:マスク、ラフネス、高さ
BC58データチャンネルデスクトップ、ゲーム機法線マップ(X と Y)
BC6H8なしデスクトップ、ゲーム機スカイボックスやライトマップなどの HDR カラー
BC78ありデスクトップ、ゲーム機アルファの有無を問わない高品質なカラー
ETC14なしほぼすべての Android非常に古い端末での不透明なカラー
ETC24–8ありAndroid、iOS広く対応しているモバイル向けの代替
ASTC0.89–8あり新しめの Android と iOS、Apple Siliconモバイルで調整可能な品質
PVRTC2–4あり古い iPhone と iPad古い Apple 端末専用
Basis ETC1S変換先によって異なるありあらゆる GPU(KTX2 経由)小さなダウンロードで、どの GPU でも動作
Basis UASTC変換先によって異なるありあらゆる GPU(KTX2 経由)高品質で、どの GPU でも動作
試してみる実際のエンコーダーを動かす当サイトのツールと同じ WebAssembly エンコーダーで 512×512 のサンプルを圧縮し、拡大した部分を比較します。
ブラウザー内で実行され、何もアップロードされません。
拡大するエリア
オリジナル
RGBA8
GPU メモリ 1 MiB
BC1
BC1
1 テクセルあたり 4 ビット
GPU メモリ 128 KiB
BC7
BC7
1 テクセルあたり 8 ビット
GPU メモリ 256 KiB
ASTC 6×6
ASTC 6×6
1 テクセルあたり 3.56 ビット
GPU メモリ 116 KiB
ASTC 12×12
ASTC 12×12
1 テクセルあたり 0.89 ビット
GPU メモリ 29 KiB

「エンコーダーを実行」を押すとサンプルを圧縮します。初回はエンコーダーをダウンロードします。

第 5 章

フォーマットの選び方

2 つの質問で候補はすぐに絞れます。どの GPU がこのテクスチャを読み込むのか、そして中身は何のデータなのか。

カラーテクスチャ、法線マップ、単一チャンネルのマスクは、圧縮に対する反応がそれぞれ異なります。また、デスクトップ、モバイル、Web では対応するフォーマットの系統も違います。自分のケースを選んで出発点を決め、実際のテクスチャで結果を確認してください。

試してみるフォーマット選択ツールテクスチャを使う環境と、その中身を選んでください。
どこで動かしますか?
テクスチャの中身は?

まずはこれ

ASTC 6×6

ほかの候補: ASTC 4×4 · ETC2 RGB

ASTC は新しめの Android と iOS の GPU で使えます。6×6 がバランスの良い選択で、重要なアセットには 4×4、古い端末には ETC2 を使います。

ASTC エンコーダーを開く

第 6 章

実践的なヒント

いくつかの習慣で、テクスチャ圧縮の問題のほとんどを防げます。

  1. 01

    カラーは sRGB、データはリニアに

    アルベドや UI のテクスチャは sRGB です。法線やラフネスなどのデータマップはリニアのままにしないと、ライティングが正しくなりません。

  2. 02

    法線マップには専用のフォーマットを

    BC5 や EAC RG11 のような 2 チャンネルフォーマットを使い、Z はシェーダーで復元します。カラー用フォーマットではビットが無駄になり、目に見える凹凸が生じます。

  3. 03

    ミップマップを生成する

    メモリは約 33% 増えますが、遠くの面のちらつきを防ぎ、サンプリングも速くなります。

  4. 04

    サイズはブロックに合わせる

    ほとんどのフォーマットは 4×4 ブロック単位なので、4 で割り切れるサイズならパディングが不要です。PVRTC などの古いフォーマットは、正方形かつ 2 のべき乗のサイズも必要です。

  5. 05

    実際のコンテンツを実機で確認する

    等倍に拡大してデコード結果と元画像を比較し、対象の GPU がそのフォーマットに対応しているか確認しましょう。

よくある質問

GPU テクスチャ圧縮は可逆ですか?

いいえ。BC、ETC、ASTC、PVRTC はブロックごとのサイズが固定された非可逆フォーマットです。どれだけ品質が落ちるかは、フォーマット、ブロックサイズ、画像の内容によります。

PNG や JPEG をそのままテクスチャに使えないのはなぜですか?

ダウンロードは速くなりますが、GPU は直接サンプリングできないため、生のテクセルにデコードされてメモリをフルに使います。GPU フォーマットはメモリ上でも小さいままです。

どのテクスチャフォーマットが一番良いですか?

デスクトップでは BC7、新しめのモバイル端末では ASTC が無難な選択です。Web のように 1 つのファイルを多くの GPU で動かす必要がある場合は、KTX2 と Basis Universal を使います。

テクセルあたりのビット数とは何ですか?

1 テクセルあたりの平均的な保存コストです。生の RGBA8 は 32 ビット、BC1 は 4 ビット、BC7 は 8 ビットで、ASTC はブロックサイズに応じて 8 ビットから約 0.89 ビットまで変わります。

自分のテクスチャで試してみましょう

すべてのエンコーダーはブラウザー内で動作します。PNG や JPEG をアップロードし、フォーマットを選んで結果を比較してください。